perm filename PARSE.OLD[AL,HE]4 blob sn#312325 filedate 1977-10-23 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00065 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00006 00002	UPDATES TO PARSE BY MSM 
C00010 00003	the AL to S-expression translator AND MSM SWITCHES
C00015 00004	! statement, operator, sex, require, move definitions
C00023 00005	! brace, condition_monitor, dimension, misc reserved word definitions
C00025 00006	! dec_name, declaration names for input and output
C00027 00007	! operators
C00032 00008	! reserved_words
C00035 00009	!	init_reserved
C00037 00010	! predefined constants
C00040 00011	! predefined macros
C00041 00012	! compiler switches and control tables
C00044 00013	! hash, declaration of debugging variables, start of hidden_parse
C00047 00014	! ---- DECLARATIONS ----
C00052 00015	!	record declarations
C00058 00016	!	other declarations
C00060 00017	! error, error_recovery, error_reject, print, file_indent
C00074 00018	! process_switches, got_input, got_output, open_logging_file, open_new_file,check_want_copy
C00081 00019	! push_source_list,pop_source_list
C00083 00020	! id info processing routines
C00085 00021	! read, push_macro_delimiters
C00089 00022	! macro handling routine
C00097 00023	! expand_macro
C00102 00024	! get_token
C00114 00025	! check_token,check_token_type
C00118 00026	! check, inverse, multiply and divide dimensions ! CHECK_EXP_TYPE_DIMENS
C00123 00027	! check_entry,insert_entry into tables
C00128 00028	! reduce, fail_up,vmake_R,vv_trans_R
C00131 00029	!	tmake_r, fmake_r
C00133 00030	!	sneg_R,rinv_R, sabs_R
C00136 00031	!	plus_R,minus_R
C00139 00032	!	times_R
C00143 00033	!	rot_R, wrt_R
C00147 00034	!	→_R
C00149 00035	!	reduce execution starts here
C00153 00036	! printexpr
C00154 00037	! string_expr
C00157 00038	! p_exp2
C00159 00039	!	parse_special
C00166 00040	!	p_exp2 execution begins here, p_exp
C00173 00041	! P_condition
C00181 00042	! P_clauses, T_gen
C00193 00043	! P_statement, F_state, modify_continue, modify_flush
C00197 00044	!	begin_P,end_P, open_paren_P
C00203 00045	!	define_P,declare_P,global_P
C00209 00046	!	if_P, plan_P, while_P
C00212 00047	!	for_P
C00215 00048	!	move_P
C00217 00049	!	affix_p,unfix_p
C00222 00050	!	signal_p, wait_p
C00224 00051	!	when_P
C00227 00052	!	dump_P
C00229 00053	!	assert_P
C00232 00054	!	on_P, reference_P
C00234 00055	!	open_P,center_P,stop_P,enable_P,disable_P
C00237 00056	!	require_P
C00244 00057	!	dimension_P
C00250 00058	!	string_P, integer_P
C00252 00059	!	abort_P, note_P,comment_P,speed_factor_P
C00255 00060	! P_statement execution starts here
C00265 00061	! execution starts here, initialization
C00268 00062	! set up input and output
C00272 00063	! set up predefined dimensions, constants, macros and variables
C00275 00064	! PARSE PROGRAM
C00277 00065	! SWAP TO AL COMPILER
C00279 ENDMK
C⊗;
COMMENT UPDATES TO PARSE BY MSM 
 9-15-77	FIXED BUG THAT MAKES INV(A)*B TO (TINVRT (TTMUL A B))
		BY ADDING "INV" TO PARSE_SPECIAL
 6- 7-77	PREDEFINED MACROS
		ADJACENT MACRO BUG FIXED
 6- 1-77	CODE FOR NEW FORCE STUFF
 5-19-77	UNARY + AND - FINALLY WORK, SIGH
 5- 3-77	STRICT DIMENSIONAL CHECKING NOW DEFAULT
 3-16-77	ENABLE/DISABLE
		MESSAGE END OF EACH BLOCK GIVING LIST OF VARIABLES NOT DEFINED AND
		NOT USED
		REMOVED PARSESHIT
 1- 9-77	MORE MEANINGFUL ERROR MESSAGES
 1- 9-77	CAN CORRECT MORE ERRORS
		WILL NOT ACCEPT DIMENSIONS ON ANYTHING EXCEPT SCALARS AND VECTORS.
 1- 5-77	ACCEPTS STRING DEFINITIONS
12-25-76	CAN CORRECT MINOR ERRORS IN SOURCE CODE IN_LINE
12-23-76	CAN ACCEPT TTY INPUT AS A FILE
12-21-76	ACCEPTS DIMENSIONS ON CONDITION MONITORS
		CREATES NEW DECLARATIONS IF UNDECLARED TERM USED IN LHS OF ASSIGNMENT
12-15-76	BAIL CAN BE CALLED IN FROM REQUIRE SWITCHES INSTRUCTIONS
		DEFAULT AND ONLY ACCEPTABLE DIMENSIONS OF FRAME IS DISTANCE
		TRANS SHOULD BE DIMENSIONLESS
12-14-76	NEW SETUP FOR RESERVED WORD DEFINITIONS, ETC.
		ERROR RECOVERY 55, WHEN FILE ASKED FOR DOES NOT EXIST
		COMBINATION OF PLUS_R,MINUS_R
		COMBINATION OF TMAKE_R, FMAKE_R
12-10-76	WHEN ERROR OF MACRO WITH PARAMETERS ACTUAL PARAMETERS SUBSTITUTED
		ACCEPTS ONLY DISTANCE VECTOR ETC NO LONGER VECTOR DISTANCE
		REQUIRE BAIL ADDED
12- 7-76	MACRO EXPANSION OF TEXT OK
12- 6-76	REQUIRE COMMENT_DELIMITERS
11-16-76	NEW CHECK_ENTRY AND INSERT_ENTRY PROCEDURES
11-15-76	INSERTION OF STRICT_DIMEN_CHECK SWITCH
		ALL PREDEFINED CONSTANTS DECLARED DIMENSIONLESS
11-14-76	DIMENSIONLESS DECLARATION COERCED TO TYPE OF EXPRESSION
		XHAT,YHAT,ZHAT MADE DIMENSIONLESS
11-6-76		NEW WAY OF COMPUTING DIMENSIONS
11-2-76		CHANGE LABEL TO STMLAB ON PG 6
11-2-76		CHANGES TO DECLARE_P TO allow default of distance to frames
11-2-76		LN49 PG 24 ADDED TO GIVE DIMENSION OF FRAME AS DISTANCE
11-2-76		ADDED ELSE DIM←0 AFTER SECOND IF STATEMENT TO CURE BUG ON PG 41 DECLARE_P
11-1-76		WOBBLE COMMAND IMPLEMENTED
10-29-76	LOGGING FEATURE IMPLEMENTED
10-27-76	TVSUB AND VSUB IMPLEMENTED
10-18-76	CHANGE STOP BLUE OR YELLOW TO STOP BARM OR YARM;

comment the AL to S-expression translator AND MSM SWITCHES;

Begin "PARSE"

REQUIRE 1024 STRING_PDL;  REQUIRE 1024 STRING_SPACE;  REQUIRE 1024 SYSTEM_PDL;
require "[][]" delimiters;

				define
α	=[begin],
β	=[end],
!	=[comment],
tab	='11,
alt	='175,
lf	='12,
ff	='14,
cr	='15,
space	='40,
dquote	='42,
squote	='47,
rubout	='177,
crlf	=[('15&'12)],
ampersand	='46,
id_hasher	=256,
macro_hasher	=16,
metric_hasher	=16,
reserved_hasher	=256,
RPTR	=[RECORD_POINTER],
RCLASS	=[RECORD_CLASS],
preload_array(name, defs, type, first, len)=[
	preload_with defs null; type array name[first:first+len] ];

! N.B. -- preload_array always creates an array 1 longer than requested;

! if /nB is set in the command line then assume he wants a debugging parser;
require "<><>" delimiters;
ifc ¬declaration(debug_compile) thenc
				define
decipher_debug(a)=<
	assignc a=cvms(compiler!banner)[2 to ∞-1];
	assignc a=cvps(a)[length(scanc(cvps(a), lf,    null, "IA"))+1 for ∞];
	assignc a=cvps(a)[length(scanc(cvps(a), tab,   null, "IA"))+1 for ∞];
	assignc a=cvps(a)[length(scanc(cvps(a), space, null, "IA"))+1 for 1];
	"a">;
    ifc decipher_debug()="0"
	thenc define debug_compile=false;
	elsec define debug_compile=true;
    endc
endc


				define
decipher_compiletime(a)=<
	assignc a=cvms(compiler!banner)[2 to ∞-1];
	assignc a=cvps(a)[length(scanc(cvps(a), tab,   null, "IA"))+6 for 21];
	"a">;

require unstack_delimiters;

require ifc ¬debug_compile
	thenc " NON-" elsec " " endc & "DEBUGGING VERSION " message;
ifc debug_compile thenc EXTERNAL PROCEDURE BAIL; 
		REQUIRE "LA" ERROR_MODES;  ! to compile and go home when system busy;
endc
				define
indices(name, postfix)=[
    redefine xxcount=0;
    redefine xx(xxarg)=[
	redefine xxtemp=[define xxarg] & [postfix=xxcount];
	xxtemp;
	redefine xxcount=xxcount+1;];
    name];

! ID postfix conventions

	_VALUE	AL data types
	_RES	reserved word types
	_beg	reserved word group begin
	_end	reserved word group end
	_R	REDUCE action routines
	_P	PARSE action routines
	_TOKEN	scanner token types
	_CM	condition monitors
	_X	indices of various sorts
	_METRIC	dimensional analysis non-sense
	_DIMEN	how to combine various matrix operands
	_TYPE	to decide which table to insert into
;

define id_type_table=0,
	macro_type_table = 1,
	macro_in_macro_type_table = 2,
	dimension_type_table =  3 ;


! **********;     require "SNAILR[AL,HE]" source_file;     ! **********;

INTEGER PROCEDURE ___TIME;
BEGIN
	INTEGER __T;
	quick_code
		setz	'13,	;
		calli	'13,'27	;
		movem	'13,__T	;
	end;
	RETURN(__T);
END;


! ************	MSM SWITCHES	*************;
DEFINE DEFIN_PRINT_SWITCH = FALSE;
! statement, operator, sex, require, move definitions;

		redefine xx(str)=[
		    redefine reserved_X_count=reserved_X_count+1;
		    redefine xx_temp="define " & "str" & "_RES=reserved_X_count";
		    xx_temp;];

		redefine yy(str,str2)=[];
		redefine zz(str)=[
		    redefine reserved_X_count=reserved_X_count+1;
		    redefine zz_temp="define " & "str" & "_RES=reserved_X_count";
		    zz_temp;];

define statement_definitions=[
xx(BEGIN)
  yy(COBEGIN)
xx(END)
  yy(COEND)
  yy([;])
zz(OPEN_PAREN)
  yy([(])
zz(DECLARE)
  yy(SCALAR,	scalar_value)
  yy(VECTOR,	vector_value)
  yy(ROT,	rot_value)
  yy(FRAME,	frame_value)
  yy(PLANE,	plane_value)
  yy(TRANS,	trans_value)
  yy(EVENT,	event_value)
  yy(ATOM,	atom_value)
  yy(WORLD,	world_value)
  yy(CM_LABEL,	cm_label_value)
  yy(CLC_LABEL,	clc_label_value)
  yy(CH_LABEL,	ch_label_value)
  yy(LABEL,	label_value)
xx(GLOBAL)
xx(IF)
xx(PLAN)
xx(WHILE)
xx(FOR)
xx(MOVE)
xx(AFFIX)
xx(UNFIX)
xx(SIGNAL)
xx(WAIT)
xx(WHEN)
xx(DUMP)
xx(ASSERT)
  yy(DENY)
xx(ON)
  yy(DEFER)
xx(REFERENCE)
xx(OPEN)
  yy(CLOSE)
xx(CENTER)
xx(STOP)
xx(SPEED_FACTOR)
xx(DEFINE)
xx(REQUIRE)
xx(DIMENSION)
xx(INTEGER)
xx(STRING)
  yy(NEW_STRING)
  yy(OLD_STRING)
xx(COMMENT)
xx(ABORT)
  yy(PRINT)
  yy(PAUSE)
xx(NOTE)
  yy(NOTE1)
  yy(NOTE2)
xx(ENABLE)
xx(DISABLE)
];
define sex_definitions = [
zz(SEX)
  yy(DSKIN)
  yy(NULL)
  yy(AFFIX)
  yy(COMMENT)
  yy(ALSO)
  yy(SPEC)
  yy(ON)
  yy(EV)
  yy(CMABLE)
  yy(UNFIX)
  yy(PR)
  yy(CLC)
  yy(CHG)
  yy(BL)
  yy(CO)
  yy(FO)
  yy(WH)
  yy(IF)
  yy(PAUSE)
  yy(ABORT)
  yy(AS)
  yy(CIF)
  yy(PAS)
  yy(ASSERT)
  yy(DENY)
  yy(AF)
  yy(SF)
  yy(MO)
  yy(OPERATE)
  yy(CENTER)
  yy(STOP)
  yy(DURATION)
  yy(FORCE)
  yy(PRINT)
  yy(VIA)
  yy(VELOCITY)
  yy(ARRIVAL)
  yy(DEPARTURE)
  yy(OPENING)
  yy(WOBBLE)
  yy(EX)
  yy(VA)
  yy(SC)
  yy(PVL)
  yy(NW)
  yy(DBD)
  yy(NOTE)
  yy(NOTE1)
  yy(NOTE2)
  yy(GAS)
  yy(NOMV)
  yy(BIND)
  yy(NOOP)
  yy(SADD)
  yy(SSUB)
  yy(SMUL)
  yy(SNEG)
  yy(SDIV)
  yy(SLT)
  yy(SEQ)
  yy(SLE)
  yy(SGE)
  yy(SNE)
  yy(SGT)
  yy(AND)
  yy(OR)
  yy(NOT)
  yy(VMAGN)
  yy(VDOT)
  yy(VMAKE)
  yy(SVMUL)
  yy(VADD)
  yy(VSUB)
  yy(RVMUL)
  yy(TVMUL)
  yy(AXIS)
  yy(RMAGN)
  yy(UVECT)
  yy(POS)
  yy(ORIENT)
  yy(RRMUL)
  yy(AXW_ROTN)
  yy(TMAKE)
  yy(FTOF)
  yy(TVADD)
  yy(TVSUB)
  yy(TTMUL)
  yy(TINVRT)
  yy(DEPR)
  yy(FMAKE)
  yy(GVAR)
  yy(SVAR)
  yy(VVAR)
  yy(TVAR)
  yy(RVAR)
  yy(FVAR)
  yy(ATOM)
  yy(EVAR)
  yy(WVAR)
  yy(CLCLAB)
  yy(CHGLAB)
  yy(OMNLAB)
  yy(STMLAB)

  yy(SPEED_FACTOR)

];
define operator_classes=[
zz(COMMA)
  yy([,])
xx(OR,	or_X)
  yy([∨],	or_X)
xx(AND,	and_X)
  yy([∧],	and_X)
xx(NOT,	not_X)
  yy([¬],	not_X)
zz(ORDER)
  yy([=],	seq_X)
  yy([≠],	sne_X)
  yy([>],	sgt_X)
  yy([<],	slt_X)
  yy([≥],	sge_X)
  yy([≤],	sle_X)
zz(ABS)
  yy([|])
  yy(VVVTRANS)
zz(ADD)
  yy([+],	plus_X)
  yy([-],	minus_X)
zz(MULT)
  yy([.],	vdot_X)
  yy([*],	times_X)
  yy([/],	sdiv_X)
  yy([⊗],	vcross_X)
  yy(WRT,	wrt_X)
  yy(VVROT,	vvrot_X)
zz(TRANS)
  yy(→,		→_X)
  yy([↑],	stos_X)
zz(VECTOR)
  yy([#],,	nomv_X)
  yy(ORIENT,	orient_X)
  yy(UNIT,	uvect_X)
  yy(AXIS,	axis_X)
  yy(POS,	pos_X)
  yy(INV,	rinv_X)
zz(CLOSE_PAREN)
  yy([)])
];
define require_definitions=[
xx(SOURCE_FILE)
xx(DELIMITERS)
xx(UNSTACK_DELIMITERS)
xx(REPLACE_DELIMITERS)
xx(MESSAGE)
xx(ERROR_MODES)
xx(COMPILER_SWITCHES)
xx(COMMENT_DELIMITERS)
xx(BAIL)
];
define move_definitions=[
xx(VIA)
xx(WITH)
xx(APPROACH)
  yy(ARRIVAL)
  yy(DEPARTURE)
xx(WOBBLE)
xx(DIRECTLY)
];

! All reserved word class id's have a postfix of "_RES".  The fact that the parser
  groups clases together is reflected by the definition of id's with "_beg" and
  "_end" postfixes.  The code demands that misc_RES be 0;

									define
sex_RES		=-2,
brace_RES	=-1,
misc_RES	=0,
cm_RES		=0,
reserved_X_count=0,

statement_beg	=reserved_X_count+1;
					statement_definitions;
									define
statement_end	=reserved_X_count,
operator_beg	=reserved_X_count+1;
					operator_classes;
									define
operator_end	=reserved_X_count,
move_beg	=reserved_X_count+1;
					move_definitions;
									define
move_end	=reserved_X_count,
require_beg	=reserved_X_count+1;
					require_definitions;
									define
require_end	=reserved_X_count+1;
					XX(METRIC)	! TIME, DISTANCE, etc.;

indices(require_definitions, _X);
indices(move_definitions, _X);
! brace, condition_monitor, dimension, misc reserved word definitions;

define brace_definitions=[
zz(BRACE)
  yy([}])
  yy([{])
];
define cm_definitions=[
zz(cm)
  qq(nil) 
  yy(FORCE,		force_cm)
  yy(TORQUE,		torque_cm)
  yy(DURATION,		duration_cm)
  yy(TEMPERATURE)
  yy(SQUEEZE)
];
define metric_definitions=[
zz(METRIC)
  qq(nil)
  yy(DISTANCE,	distance_METRIC)
  yy(TIME,	time_METRIC)
! yy(MASS,	mass_METRIC)	;
  yy(ANGLE,	angle_METRIC)
  yy(FORCE,	force_metric)
];
define misc_definitions=[
zz(MISC)
  yy([?])
  yy(ABS)
  yy(TO)
  yy(TRACING)
  yy(WHERE)
  yy(THEN)
  yy(DO)
  yy(FORM)
  yy(AT)
  yy(BY)
  yy(CHANGING)
  yy(ALSO)
  yy(DONT)
  yy(ONLY)
  yy(RIGIDLY)
  yy(NONRIGIDLY)
  yy(STEP)
  yy(UNTIL)
  yy(ELSE)
];


redefine zz(str)=[];
redefine qq(str)=[
	redefine qq_temp=[xx(str)];
	qq_temp;];
redefine yy(str,str2)=[
	redefine yy_temp=[xx(str)];
	yy_temp;];

indices(metric_definitions, _METRIC);
		define
metric_max	=xxcount-1;

indices(cm_definitions, _CM);





EVALdefine basic_dimensions=[
redefine zz(str,str2)=[];
redefine qq(str,str2)=[];
redefine yy(str,str2)=[xx(str)];
metric_definitions
];



! dec_name, declaration names for input and output;

! don't juggle the order of these definitions, because the parse will cease to
  function;

define dec_name_definitions=[
xx(SCALAR,	SVAR)
xx(VECTOR,	VVAR)
xx(ROT,		RVAR)
xx(FRAME,	FVAR)
xx(PLANE,	PVAR)
xx(TRANS,	TVAR)
xx(EVENT,	EVAR)
xx(ATOM,	ATOM)
xx(WORLD,	WVAR)
xx(CM_LABEL,	OMNLAB)
xx(CLC_LABEL,	CLCLAB)
xx(CH_LABEL,	CHGLAB)
xx(LABEL,	STMLAB)
];

	! data types;

		DEFINE
string_VALUE	=-2,
form_VALUE	=-1,
boole_VALUE	=0;		! others follow directly;

		define
dec_name_count=0;
		redefine xx(in, out)=[
		    redefine dec_name_count=dec_name_count+1;
		    redefine xx_temp="define in" & "_VALUE=" & cvms(dec_name_count);
		    xx_temp;];
		dec_name_definitions;
define frame_exp_VALUE=trans_VALUE;	! COERCION DICTATES THAT THESE BE THE SAME;

		redefine xx(in, out)=["out",];
		preload_array(
dec_name, dec_name_definitions, string, 1, dec_name_count);
! operators;

! **********     WARNING!!!!!     **********
  keep all entries marked TRUE contiguous
  don't disturb the order of this table ;

define operator_definitions=[
XX(NOT,		1,	FALSE,	boole,	boole,	ignore)
XX(AND,		2,	FALSE,	boole,	boole,	ignore)
XX(OR,		2,	FALSE,	boole,	boole,	ignore)
XX(SEQ,		2,	FALSE,	boole,	scalar,	ignore)
XX(SNE,		2,	FALSE,	boole,	scalar,	ignore)
XX(SGT,		2,	FALSE,	boole,	scalar,	ignore)
XX(SLT,		2,	FALSE,	boole,	scalar,	ignore)
XX(SGE,		2,	FALSE,	boole,	scalar,	ignore)

XX(SLE,		2,	FALSE,	boole,	scalar,	ignore)
XX(UVECT,	1,	FALSE,	vector,	vector,	same)
XX(AXIS,	1,	FALSE,	vector,	rot,	ignore)
XX(POS,		1,	FALSE,	vector,	trans,	ignore)
XX(ORIENT,	1,	FALSE,	rot,	trans,	ignore)

XX(TMAKE,	2,	TRUE,	trans,	boole,	ignore)
XX(VMAKE,	3,	TRUE,	vector,	scalar,	ignore)
XX(FMAKE,	2,	TRUE,	trans,	boole,	ignore)
XX(VVTRANS,	3,	TRUE,	trans,	scalar,	ignore)
!   XX(SNEG,	1,	TRUE,	scalar,	scalar,	same) ;

XX(RINV,	1,	TRUE,	scalar,	scalar,	inverse)
XX(SABS,	1,	TRUE,	scalar,	scalar,	same)
XX([+],		2,	TRUE,	scalar,	scalar,	check,		PLUS)
XX([-],		2,	TRUE,	scalar,	scalar,	check,		MINUS)
XX([*],		2,	TRUE,	scalar,	scalar,	multiply,	TIMES)

XX(WRT,		2,	TRUE,	scalar,	scalar,	multiply)

XX(ROT,		2,	TRUE,	vector,	boole,	ignore)
XX(→,		2,	TRUE,	trans,	boole,	divide)
XX(VDOT,	2,	FALSE,	scalar,	vector,	multiply)
XX(ANGLE,	2,	FALSE,	scalar,	vector,	ignore)
XX(VCROSS,	2,	FALSE,	vector,	vector,	multiply)

XX(VVROT,	2,	FALSE,	rot,	vector,	ignore)
XX(SDIV,	2,	FALSE,	scalar,	scalar,	divide)
XX(STOS,	2,	FALSE,	scalar,	scalar,	ignore)
XX(NOMV,	1,	FALSE,	form,	form,	same)
];

		define
first_true_op=-1,
op_count=0;
		redefine xx(str1, i1, boole, i2, i3, i4, str2)=[
			redefine op_count=op_count+1;
			ifc "str2"=null
			    thenc redefine xxtemp=[define str1] & "_X=op_count";
			    elsec redefine xxtemp=[define str2] & "_X=op_count";
			endc
			xxtemp;
			ifc first_true_op<0 and boole
				thenc redefine first_true_op=op_count; endc];
		operator_definitions;

		define zap_op(name, type, arg, postfix)=[
		    ifc "postfix"=null
			thenc redefine xx(str1, i1, boole, i2, i3, i4, str2)=[arg,];
			elsec redefine xx(str1, i1, boole, i2, i3, i4, str2)=
			    [arg]&[postfix,];
		    endc
		    preload_array(name, operator_definitions, type, 1, op_count)];

					zap_op(
op_array,	string, "str1");
					zap_op(
op_num,		integer, i1);
					zap_op(
op_bool,	boolean, boole);
					zap_op(
result_type,	integer, i2, _VALUE);
					zap_op(
type_of_args,	integer, i3, _VALUE);

	! specifies how to work out new DIMENSION of argument ;

		define
	ignore_dimen	=0,
	same_dimen	=1,
	inverse_dimen	=2,
	check_dimen	=3,
	multiply_dimen	=4,
	divide_dimen	=5;

					zap_op(
dimen_changes,	integer, i4, _dimen);
! reserved_words;


define reserved_definitions=[
brace_definitions
cm_definitions
statement_definitions
operator_classes
require_definitions
move_definitions
misc_definitions
sex_definitions
];

		define
reserved_count=0;
		redefine zz(name)= [];
		redefine qq(name)= [];
		redefine xx(name)=[
		    redefine reserved_count=reserved_count+1;];
		redefine yy(name, special)=[
		    redefine reserved_count=reserved_count+1;];
		reserved_definitions;
		redefine xx(name)=["name",];
		redefine yy(name,special)=["name",];
		preload_array(
reserved_words,	reserved_definitions, string, 1, reserved_count);
		redefine zz(name)=[
			redefine class=["name"];
			];
		redefine xx(name)=[
			redefine xxtemp=[name] & "_RES";
			redefine class=["name"];
		    xxtemp,];
		redefine yy(name,special)=[
			redefine yytemp= class &"_RES";
		    yytemp,];
		preload_array(
reserved_class,	reserved_definitions, integer, 1, reserved_count);
		redefine xx(name)=[0,];
		redefine yy(name, special)=[
		    ifc "special"=null thenc 0 elsec special endc,];
		preload_array(
reserved_special, reserved_definitions, integer, 1, reserved_count);

whilec [reserved_count > 9*reserved_hasher/10] doc
	[require "
RESERVED TABLE NOT BIG ENOUGH, WILL DOUBLE IT.
" message ;

	redefine reserved_hasher=reserved_hasher+reserved_hasher;]
					endc
		string array
reserved[0:reserved_hasher-1];
		integer array
com_type[0:reserved_hasher-1];

!	init_reserved;

forward SIMPLE INTEGER PROCEDURE HASH(STRING S;INTEGER MAX);

procedure init_reserved;
    α string s; integer i, k;

    boolean procedure find_sym(string s; reference integer k);
	α string probe;
	k ← hash(s, reserved_hasher);
	while (probe ← reserved[k])≠null do
	    if equ(s, probe) then return(true) else k ← (k+1) mod reserved_hasher;
	return(false);
	β;

    arrclr(reserved); arrclr(com_type);
    for i ← 1 step 1 until reserved_count do
	if find_sym(reserved_words[i], k)
	    then α if reserved_class[i] ≠ SEX_RES then
		 	outstr(reserved_words[i] & " doubly defined!" & crlf);
		 β
	    else
		α
		reserved[k] ← reserved_words[i];
		com_type[k] ← reserved_class[i]+reserved_special[i]*reserved_hasher;
		β;
require "<><>" delimiters;
    s ← decipher_compiletime();
require unstack_delimiters;
    outstr("COMPILED "&s&crlf);
    β;	

require init_reserved initialization [0];
! predefined constants;

define constant_definitions=[
XX(GARB_ID,	scalar,	nil)			! do not move this entry;

XX(PI,		scalar,	nil)
XX(π,		scalar,nil)
XX(INCH,	scalar, distance)
XX(INCHES,	scalar, distance)
XX(CM,		scalar,	distance)
XX(SEC,		scalar,	time)
XX(SECONDS,	scalar,	time)
!	XX(GM_MASS,	scalar,	mass)	;
XX(DEG,		scalar,	angle)
XX(DEGREES,	scalar, angle)
XX(RADIANS,	scalar,	angle)
XX(GM,		scalar,	force)
XX(OZ,		scalar, force)
XX(LBS,		scalar, force)
XX(OUNCES,	scalar,	force)

XX(XHAT,	vector,	nil)
XX(YHAT,	vector,	nil)
XX(ZHAT,	vector,	nil)
XX(NILVECT,	vector,	nil)

XX(NILROTN,	rot,	angle)
XX(NILTRANS,	trans,	nil)

XX(STATION,	trans,	distance)
XX(YPARK,	trans,	distance)
XX(BPARK,	trans,	distance)

XX(YARM,	trans,	distance)
XX(BARM,	trans,	distance)

XX(YHAND,	scalar,	distance)
XX(BHAND,	scalar,	distance)

XX(TRUE,	boole,	nil)
XX(FALSE,	boole,	nil)

XX(CRLF,	string,	nil)
];

		define
 const_count = 0;
		redefine xx(str, i1, i2)=[redefine const_count = const_count+1;];
		constant_definitions;

		define zap_const(name, type, arg, postfix)=[
		    ifc "postfix"=null
			thenc redefine xx(str, i1, i2)=[arg,];
			elsec redefine xx(str, i1, i2)=[arg] & [postfix,];
		    endc
		    preload_array(name, constant_definitions, type, 1, const_count)];

					zap_const(
preconst,	string, "str");
					zap_const(
preconst_type,	integer, i1, _VALUE);
					zap_const(
pre_dimens,	integer, i2, _METRIC);
! predefined macros;

define macro_definitions=[
! XX(DIRECTLY,	[ WITH APPROACH = NILDEPROACH WITH DEPARTURE = NILDEPROACH]);
XX(NON_BEGINNER,	[BEGIN  REQUIRE ERROR_MODES ""F"";])
XX(CAUTIOUS,	[ SPEED_FACTOR ← 2.0])
XX(SLOW,	[ SPEED_FACTOR ← 3.0])
XX(CAUTIOUSLY,	[ WITH SPEED_FACTOR = 2.0])
XX(SLOWLY,	[ WITH SPEED_FACTOR = 3.0])
XX(SETUP_BARMF,	[ FRAME BARMF; 
		AFFIX BARMF TO BARM AT TRANS(ROT(XHAT,180*DEG),NILVECT*INCHES) RIGIDLY; ])
];
! compiler switches and control tables;

! As the AL compile time system runs,  several intermediate files are created
  and destroyed.  The default extensions of these files are listed below.

    .AL		user	the ALGOL like AL source language
    .LOG	user	file of errors detected by the PARSER
    .SEX	AL	s-expression version of AL source code
    .ALP (.AL0)	ALC	pseudo code
    .ALT (.AL1)	ALC	trajectory file
    .ALV (.AL2)	ALC	constants and variable definitions for pseudo code
    .ALS (.AL3)	ALC	symbol table usable by the PDP-11 runtime system
    .ALL	ALC	hybrid s-expression/real AL listing
    .LST	PALX	PDP-11 assembly code listing
    .BIN	PALX	PDP-11 binary file loaded by 11TTY
    .DMP	11TTY	PDP-11 core image
;

! compiler switches;

define compiler_switches=[
xx(K, false)	! keep extraneous intermediate files:  .ALP, .ALV, .ALT;
xx(S, false)	! inhibit the deletion of the .SEX file;
xx(L, false)	! generate a PALX assembly listing;
xx(B, false)	! run BAIL immediately after scanning the command line;
xx(E, false)	! load the .BIN file into the PDP-11;
];

indices(compiler_switches, _X);
		define
switch_max	=xxcount-1;
			redefine xx(name, default)=["name",];  preload_array(
switch_name,	compiler_switches, string, 0, switch_max+1);
			redefine xx(name, default)=[default,];  preload_array(
switch_default,	compiler_switches, boolean, 0, switch_max+1);
		boolean array
switch_setting[0:switch_max];

procedure preset_switches;
    α integer i;
    for i ← 0 step 1 until switch_max do switch_setting[i] ← switch_default[i];
    β;

require preset_switches initialization[0];
! hash, declaration of debugging variables, start of hidden_parse;

SIMPLE INTEGER PROCEDURE HASH(STRING S;INTEGER MAX);
    α INTEGER I,TOT,C;
    C←I←1;  TOT←0;
    WHILE I≠0 DO TOT←TOT+(C←C+1)*(I←LOP(S));
    RETURN(TOT MOD MAX);
    β;

ifc debug_compile thenc	! some variables that can be used for debugging;
	require "BREAK.HDR[1,PJ]" source_file;
							RPTR(any_class)
__r0, __r1, __r2, __r3, __r4, __r5, __r6, __r7, __r8, __r9;
								string
__s0, __s1, __s2, __s3, __s4, __s5, __s6, __s7, __s8, __s9;
								integer
__i0, __i1, __i2, __i3, __i4, __i5, __i6, __i7, __i8, __i9;
								real
__x0, __x1, __x2, __x3, __x4, __x5, __x6, __x7, __x8, __x9;

procedure debug_init;
    α
__r0 ← __r1 ← __r2 ← __r3 ← __r4 ← __r5 ← __r6 ← __r7 ← __r8 ← __r9 ← null_record;
__s0 ← __s1 ← __s2 ← __s3 ← __s4 ← __s5 ← __s6 ← __s7 ← __s8 ← __s9 ← null;
__i0 ← __i1 ← __i2 ← __i3 ← __i4 ← __i5 ← __i6 ← __i7 ← __i8 ← __i9 ← 0;
__x0 ← __x1 ← __x2 ← __x3 ← __x4 ← __x5 ← __x6 ← __x7 ← __x8 ← __x9 ← 0.0;
    β;

require debug_init initialization[0];

endc

! The following (making all of parse a recursive procedure) is a hack to get the
	restart option to work properly.  As soon as a better way is found of
	making sure everything gets reinitialized properly, this should be taken
	out;
recursive procedure  hidden_parse;
α "hidden_parse"
! ---- DECLARATIONS ----;

		external integer
rpgsw;
		RPTR(file)
AL_file,		! AL source file;
SEX_file,		! s-expression file;
BIN_file,		! PALX binary file;
ALL_file,		! ALC listing file;
LOG_file,		! LOG listing file;
PRESENT_file;		! Present file;
		BOOLEAN
DISK,			! TRUE IF INPUT IS COMING FROM DISK;
AUTO_PROCEED,		! TRUE IF AUTO_PROCEED SWITCH IS ON FOR ERROR RECOVERY;
LOGGING,		! TRUE IF LOGGING WANTED;
COMPILE_LOGGING,	! TRUE IF LOGGING WANTED THROUGH REQUIRE STATEMENT;
LOG_FILE_OPEN,
STRICT_DIMEN_CHECK;	
		STRING
cmd_line,
INFILE,
OUTFILE,		! INPUT,OUTPUT & LOG FILES;
LOGFILE;
		INTEGER
CHANIN,
CHANOUT,
CHANTTYO,
CHANLOG;
		STRING
INSTRING,		! INPUT STRING;
TABLE1;			! BREAK TABLES;


	!  GET_TOKEN VARIABLES;
		REAL
REALNUM;
		INTEGER
TYPE_OF_RES_WORD,	! TYPE PULLED OFF OF COM_TYPE;
SPECIAL_INFO,		! INFO PASSED FROM SCANNER TO PARSER - DEPENDS ON TYPE;
ID_TYPE,
BLOCK_LEVEL_OF_DEFN,
RESERVED_TOKEN_PTR,
TYPE_OF_TOKEN;
		define
	special_token	=-1,
	undeclared_token=0,
	id_token	=1,
	numeric_token	=2,
	string_token	=3,
	macro_token	=4,
	macro_body_token=5,
	metric_token	=6,
	reserved_token	=7;
		STRING PROCEDURE TOKEN_TYPE_TRANSFORM;
		  α string s1;
		  s1← CASE TYPE_OF_TOKEN OF ( "undeclared","id","numeric",
			"string","macro","macro_body","metric","reserved");
		  return(s1&"_type");
		  β;

		STRING PROCEDURE ID_TYPE_TRANSFORM;
		  α string s1;
		  s1← CASE (ID_TYPE + 2 )OF ("string","form","boole","scalar",
			"vector","rot","frame","plane","trans","event","atom",
			"world","on_label","calculator_label",
			"changer_label","statement_label");
		  return(s1&"_type");
		  β;

		STRING
TOKEN,
TOKEN_FRONT;
		RPTR(ANY_CLASS)
TOKEN_PTR;

	! END GET_TOKEN VARIABLES;

		integer
word_R_break,		! break tables;
non_blank_break,
word_S_break,
close_brace_break,
non_digit_break,
quote_break,
macro_delimiter_break,
semicolon_A_break,
cr_break,
paren_cr_break,
lf_ff_break,
semicolon_R_break,
omit_break,
tty_input_break;
		STRING
CURRENT_FRAME;		! TOKEN OF THE CURRENT FRAME - DEFAULT SET TO "YARM";
		INTEGER
SPACING;		! SPACING FOR OUTPUT;
		BOOLEAN
REJECT;			! TRUE WHEN THE LAST TOKEN IS REJECTED BY THE CALLING PROC;
		INTEGER
DEC_NUM,		! THE NUMBER OF DECLARATIONS IN THE CURRENT BLOCK;
MACRO_DEC_NUM,		! THE NUMBER OF MACROS IN CURRENT BLOCK;
DIMEN_DEC_NUM;		! THE NUMBER OF DIMENSIONS IN THE CURRENT BLOCK;
		STRING
OUTEXPR;		! FOR THE CONSTRUCTION OF THE STRING FOR EXPRESSIONS;
		STRING
OPEN_BRACE;
		INTEGER
CHECK_TYPE_VAR;		! RETURNS TYPE OF ID FROM CHECK_ENTRY;
		STRING
MACRO_STRING;

	! ERROR VARIABLES;
		BOOLEAN
INSIDE_MACRO_DEFINITION,
INSIDE_DECLARE_P,
INSIDE_CONDITION_MONITOR,
INSIDE_STRING_DECLARATION,
INITIALIZE,		! INITIALIZATION PROCESS;
CAN_MODIFY,		! FOR ERRORS;
PATCH_CODE,		! TO PATCH CODE;
MODIFIED,
BACKUP_MODIFY,
BACKUP_MODIFIED,
PROMPT_FOR_MODIFIABLE_ERROR_ONLY;
		INTEGER
NUM_OF_ERRORS,
INSIDE_STATEMENT,
NUM_OF_ERRORS_FLUSHED,
NUM_OF_ERRORS_MODIFIED;
		STRING
BACKUP_ERROR_BUFFER,
ERROR_BUFFER;
	! END ERROR VARIABLES;

		INTEGER
RUNTIME;
!	record declarations;



		RCLASS
PARAM_LIST(
		STRING
    ID,
    USER_ID;
		RPTR(PARAM_LIST)
    NEXT
);



		RCLASS
MACRO_LIST(
		STRING
    VALUE,		! ACTUAL MACRO body;
    ID,
    DELIMITERS;
		INTEGER
    NUM;		! NUMBER OF PARAMETERS;
		RPTR(MACRO_LIST)
    NEXT,		! POINTS TO NEXT MACRO WHICH HASHES TO THE SAME ENTRY;
    LAST,		! BACK POINTER IN THE SAME LIST;
    LINK;		! USED ONLY FOR PARAMETER EXPANSION, POINTS TO THE
			  PARAMETER DEFINED JUST BEFORE THIS ONE;
		RPTR(PARAM_LIST)
    PARAMS;
		INTEGER
    BLOCK_LEVEL_OF_DEFN
);

		RPTR(MACRO_LIST)
TOP_PARAM,
current_macro,
TOP_MACRO,
CUR_MACRO;
		RPTR(MACRO_LIST) ARRAY
MACRO_TABLE[0:macro_hasher];


		RCLASS
DELIMITER_LIST(
		STRING
    D1,
    D2;
		RPTR(DELIMITER_LIST)
    NEXT
);
		RPTR(DELIMITER_LIST)
TOP_DELIMITERS;


		RCLASS
MACRO_STACK(
		RPTR(MACRO_LIST)
    LIST_PTR;
		RPTR(MACRO_STACK)
    STACK_LINK
);
		RPTR(MACRO_STACK)
MACRO_STACK_TOP,
MACRO_ST2;
		RCLASS 
MACRO_CONCATENATE_LIST(
		RPTR(MACRO_LIST)
    MACRO_PTR;
		RPTR(MACRO_CONCATENATE_LIST)
    NEXT
);

		RPTR(MACRO_CONCATENATE_LIST)
MACRO_CON_HEAD;

		RCLASS
DIMENS_EXPONENT(
		STRING
    NAME;
		INTEGER
    DISTANCE,
    TIME,	! GIVES EXPONENTS OF VARIOUS COEFFICIENTS;
    MASS,
    ANGLE,
    FORCE;
		RPTR(DIMENS_EXPONENT)
    NEXT,
    LAST;
		INTEGER
    BLOCK_LEVEL_OF_DEFN
);
		RPTR(DIMENS_EXPONENT)
NIL_DIMENS,
DISTANCE_DIMENS,
TIME_DIMENS,
		!	MASS_DIMENS;
ANGLE_DIMENS,
FORCE_DIMENS,
TORQUE_DIMENS,
VELOCITY_DIMENS,
ANGULAR_VELOCITY_DIMENS,
TOP_DIMENS,	! POINTS TO TOP MACRO IN THIS BLOCK;
EXP_DIMENS;

		RPTR(DIMENS_EXPONENT) ARRAY
DIMENS_TABLE[0:metric_hasher],
D_TABLE[0:metric_max];



		RCLASS
ID_LIST(
		STRING
    NAME,
    BODY;
		INTEGER
    FLAGS,
    TYPE;
		RPTR(ID_LIST)
    NEXT,		! POINTS TO NEXT ID WHICH HASHES TO THE SAME ENTRY;
    LAST;		! POINTS TO THE ID DEFINED JUST BEFORE THIS ONE;
		RPTR(DIMENS_EXPONENT)
    DIMEN;
		INTEGER
    BLOCK_LEVEL_OF_DEFN
);
		RPTR(ID_LIST) ARRAY
SYMBOL_TABLE[0:id_hasher];
		RPTR(ID_LIST)
TOP_ID;



		RCLASS
EXPR(
		INTEGER
    TYPE;
		STRING
    OP,
    ID;
		RPTR(DIMENS_EXPONENT)
    DIMEN;
		RPTR(ANY_CLASS)
    PARTS
);
		RPTR(EXPR)
EXP1,
EXP2,
EXP3;



		RCLASS
EXPR_LIST(
		RPTR(EXPR)
    EXP;
		RPTR(EXPR_LIST)
    NEXT
);
		RPTR(EXPR_LIST)
EXPRS,
EXPRSAVE;

		RCLASS
OP_LIST(
		RPTR(OP_LIST)
    NEXT;
		INTEGER
    PRIORITY,
    OP,
    NUM_OF_ARGS,
    COUNT;
		BOOLEAN
    ARG_DEP,
    FUNC
);
		RPTR(OP_LIST)
OPS,
OPSAVE;

		RCLASS
SOURCE_LIST(
		INTEGER
    CHAN,		! i/o CHANNEL NUMBER OF input, -1 if from macro;
    NUM,		! NUMBER OF PARAMETERS IN THE CURRENT MACRO;
    PN,
    LN;			! PAGE AND LINE NUMBER OF THE PUSHED FILE;
		STRING
    CUR_STRING,		! curline WHEN PUSHED;
    CUR_STRINGR,	! curliner WHEN PUSHED;
    FILE_NAME,		! NAME OF THE INPUT FILE WHEN PUSHED;
    MACRO_STRING;
		RPTR(SOURCE_LIST)
    NEXT;
		RPTR(MACRO_STACK)
    MACRO_STACK_TOP;
		RPTR(MACRO_LIST)
    CUR_MACRO;
		RPTR(FILE)
    FILE_PTR;
		INTEGER
    CHANTTYO
);
		RPTR(SOURCE_LIST)
TOP_SOURCE;
!	other declarations;
		INTEGER
EXP_TYPE;		! TYPE OF EXPRESSION FOUND BY P_EXP;
		BOOLEAN
PLAN_STATEMENT;		! TRUE IF CURRENT STATMENT IS PREFIXED BY PLAN;
		STRING
CHANGER_HEAD;		! NON NULL IF PARSING A STATEMENT INSDIDE A CHANGER;
		INTEGER
T_COUNT,		! COUNTER FOR PRODUCING UNIQUE ID'S;
S_COUNT;		! COUNTER FOR PRODUCING UNIQUE SCALARS;
		BOOLEAN
NO_OP_SO_FAR,
OP_EXPECTED;		! TRUE WHEN P_EXP EXPECTS AN OPERATION;

		INTEGER
DELIMITER_1,		! non-zero only while defining macro;
DELIMITER_2;		! HEAD AND TAIL DELIMITER OF macro bodies;
		INTEGER
MAC_NUM;		! NUMBER OF PARAMS IN THE CURRENT MACRO EXPANSION;
		INTEGER
BLOCK_LEVEL;
! GARBAGE DECLARATIONS (VERY LOCAL);

		BOOLEAN
T,
EOF;
		INTEGER
COUNT,
I,
N,
BRCHAR;
		STRING
GARB;
		INTEGER
LINENUM,
PAGENUM,
SOSNUM,
typed_page_num,	! on tty;
sourcelvl;
		STRING
CURLINER,
CURLINE;

! error, error_recovery, error_reject, print, file_indent;

FORWARD RECURSIVE PROCEDURE P_STATEMENT;

forward procedure add_to_table1(string s);
FORWARD RECURSIVE PROCEDURE GET_TOKEN;

FORWARD PROCEDURE OPEN_LOGGING_FILE;

forward RPTR (ANY_CLASS) PROCEDURE CHECK_ENTRY (STRING S; INTEGER TABLE_TYPE);
forward RPTR (ANY_CLASS) PROCEDURE INSERT_ENTRY (STRING S;
	INTEGER TABLE_TYPE; RPTR(ANY_CLASS) RR1(NULL_RECORD));

forward boolean procedure got_output(RPTR(file) F);

RPTR(ANY_CLASS) PROCEDURE ERROR(INTEGER I;STRING S);

	! I don't understand the error number stuff.  All errors numbered 200
	  have been added by me and can be arbitrarily reassigned.

					PJ 8/30/76;

α INTEGER L1,L2;  BOOLEAN PROCEED;  INTEGER COMMAND_CHAR; BOOLEAN TERSE;
RPTR(ANY_CLASS) PROCEDURE ERROR_RECOVERY(INTEGER I);
IF I=13 THEN α RPTR(ID_LIST)D1;
	OUTSTR(CRLF& "Continue will declare it internally");
	D1←INSERT_ENTRY(TOKEN,ID_TYPE_TABLE);
	ID_LIST:TYPE[D1]←TRANS_VALUE;
	ID_LIST:BLOCK_LEVEL_OF_DEFN[D1]←BLOCK_LEVEL;
	RETURN(D1);
	β
ELSE 
IF I=55 THEN α  string s; s←null;
	WHILE LENGTH(S)=0 AND ¬AUTO_PROCEED DO α
	OUTSTR(CRLF& "Type in correct file"&crlf& "*");
	s←inchwl; PROCEED←TRUE;
	if length(s)≠0 then infile←s;
			β;
	RETURN(NULL_RECORD);
	β
ELSE
RETURN(NULL_RECORD);

RPTR(ANY_CLASS) C1;
string source_pos;
STRING LINE,LINER;
source_pos←"File "& INFILE& ", Page "& CVS(PAGENUM+1)& ", Line "& CVS(LINENUM);
LINE←CURLINE; LINER←CURLINER;
IF CHANIN≤-1 THEN α ! SUBSTITUTE DUMMY PARAMETERS OF MACRO FOR REAL THING;
		INTEGER I1,PARAM_COUNT;
		source_pos← "At "&source_pos&crlf&"inside Macro "¯o_list:id[current_macro];
		if liner=space then liner←liner[2 to ∞];
		IF (PARAM_COUNT←SOURCE_LIST:NUM[TOP_SOURCE]) > 0
		THEN α
			string array param_id,param_arg[1:param_count];
			RPTR(param_list) param_ptr;
			integer l1,l2,temp;
			string t;

			string procedure subst(string old_string);
			α string t,t1,old;
			integer brchar,i1;
			old←old_string;
			t←scan(old,temp,brchar);
			while brchar≠0 do
				α t1←old[1 to l1];
				  old←old[l2 to ∞];
				  for i1←1 step 1 until param_count do
					if equ(t1,param_arg[i1]) 
					then t←t¶m_id[i1];
				  t←t&scan(old,temp,brchar);
				β;
			return(t);
			β;

			param_ptr←macro_list:params[current_macro];
			source_pos←source_pos&"(";
			for i1←1 step 1 until param_count do
				α param_arg[i1]←param_list:id[param_ptr];
				  param_id[i1]←param_list:user_id[param_ptr];
				  param_ptr←param_list:next[param_ptr];
				  source_pos←source_pos¶m_id[i1]&",";
				β;
			l1←length(source_pos);
			source_pos←source_pos[1 to l1-1]&")"&crlf;
			l2←(l1←length(param_arg[1]))+1;
			t←param_arg[1][1 for 1];
			setbreak(temp←getbreak,t,null,"INR");
			line←subst(line);
			liner←subst(liner);
			RELBREAK(TEMP);
			β;
		β;
WHILE EQU(LINE[1 TO 1], lf) DO GARB←LOP(LINE);
L1←LENGTH(LINER);  L2←LENGTH(LINE)-L1;  PROCEED←AUTO_PROCEED;
IF ¬PROMPT_FOR_MODIFIABLE_ERROR_ONLY OR CAN_MODIFY
  then	α
	IF CAN_MODIFY THEN PROCEED←FALSE;
ifc debug_compile thenc
	OUTSTR(crlf & "ERROR TYPE " & CVS(I));
endc
	OUTSTR(crlf & S & crlf
	& source_pos & crlf & LINE[1 TO L2] & lf & LINER & crlf);
	β
	ELSE IF PROMPT_FOR_MODIFIABLE_ERROR_ONLY THEN PROCEED←TRUE;
C1←ERROR_RECOVERY(I);
IF ¬LOGGING THEN IF COMPILE_LOGGING THEN OPEN_LOGGING_FILE;
IF LOGGING THEN
	OUT(CHANLOG,crlf & "ERROR TYPE " & CVS(I) & crlf & S & crlf
		& source_pos & crlf & LINE[1 TO L2] & lf & LINER & crlf);
WHILE ¬PROCEED DO
	α
	CLRBUF; OUTSTR("$"); DO COMMAND_CHAR←INCHRS UNTIL COMMAND_CHAR<0;
	COMMAND_CHAR←INCHRW;
	CASE COMMAND_CHAR OF
		α

	["B"]	α
		OUTSTR("ail" & crlf);
			IFC debug_compile
				THENC BAIL
				ELSEC OUTSTR("Sorry, Bail not loaded." & crlf)
			ENDC;
		β;

	[cr] 	α CLRBUF; PROCEED←TRUE; β;

	["C"]	α OUTSTR("ontinue with default recovery"); PROCEED←TRUE; β;

	[lf]	α PROCEED←TRUE; AUTO_PROCEED←TRUE; β;

	["A"]	α OUTSTR("utomatic continuation");
		IF LOGGING THEN OUTSTR(" and logging");
		OUTSTR(".");
		PROCEED←TRUE; AUTO_PROCEED←TRUE;
		β;

	["E"]	α OUTSTR("dit" & crlf);
		CLOSO(CHANLOG);CLOSO(CHANOUT);
		EDFILE(INFILE,LINENUM,PAGENUM+1,0); 
		β;

IFC DEBUG_COMPILE THENC
	["∂"]	α 
		OUTSTR("   special debugger"&CRLF); ! for quick debugging without invoking BAIL;
		OUTSTR("TOKEN=	"&TOKEN&" ;	TYPE_OF_TOKEN = "&TOKEN_TYPE_TRANSFORM&CRLF);
		IF INSIDE_STATEMENT ≥0 THEN OUTSTR(";	INSIDE STATEMENT "&RESERVED[INSIDE_STATEMENT]&CRLF);
		IF TYPE_OF_TOKEN=ID_TOKEN THEN OUTSTR(";	ID_TYPE= "& ID_TYPE_TRANSFORM&CRLF);
		OUTSTR("CURLINER =  " & CURLINER & CRLF & "CURLINE = "& CURLINE &CRLF);
		β;

	["ε"]	α STRING SS;
		OUTSTR("   special debugger"&crlf);  ! for quick debugging ;
		outstr("number of errors = 	"&CVS(NUM_OF_ERRORS)&CRLF&
			"number of errors modified =	"&cvs(NUM_OF_ERRORS_MODIFIED)&CRLF&
			"number of errors flushed =	"&cvs(NUM_OF_ERRORS_FLUSHED)&CRLF);
		OUTSTR("RESET THESE COUNTERS?");
		IF (SS←INCHRW)="Y" THEN NUM_OF_ERRORS←NUM_OF_ERRORS_MODIFIED←NUM_OF_ERRORS_MODIFIED←0;
		β;
	ENDC

	["R"]	α
		OUTSTR("estart"); CURLINE←CURLINER←null;
		USERERR(0,1,NULL,"S");		! THIS IS A HACK AND SHOULD BE CHANGED
						  AS SOON AS POSSIBLE;
		β;

	["X"]	α OUTSTR("it" & crlf);
		USERERR(0,1,NULL,"X");		! DITTO ABOVE COMMENT;
		β;

	["M"]	IF CAN_MODIFY THEN
			α
			OUTSTR("odify the following line"&CRLF);
			CLRBUF;
			LODED(ERROR_BUFFER);
			ERROR_BUFFER←INCHWL;
			MODIFIED←PROCEED←TRUE;
			CAN_MODIFY←FALSE;
			NUM_OF_ERRORS_MODIFIED←NUM_OF_ERRORS_MODIFIED+1;
			β
		  ELSE  OUTSTR("odify - ******* - sorry, non-modifiable error"&CRLF);

	["T"]	α OUTSTR("erse" & crlf); TERSE←TRUE;	β;

	["V"]	α OUTSTR("erbose" & crlf);  TERSE←FALSE; β;

	["P"]	IF PATCH_CODE THEN
			α
			OUTSTR("atch source code; modify following line"&CRLF);
			CLRBUF;
			LODED(LINER);
			CURLINER←INCHWL;
			CURLINE←LINE[1 TO L2] & CURLINER;
			PATCH_CODE←FALSE;
			PROCEED←TRUE;
			NUM_OF_ERRORS_MODIFIED←NUM_OF_ERRORS_MODIFIED+1;
			β
		   ELSE OUTSTR("atch - ***** sorry, non-patchable error *****"&CRLF);


	["G"]	IF BACKUP_MODIFY THEN
			α OUTSTR("  Modify the following line" & CRLF);
			CLRBUF;
			LODED(BACKUP_ERROR_BUFFER);
			BACKUP_ERROR_BUFFER←INCHWL;
			BACKUP_MODIFIED←PROCEED←TRUE;
			BACKUP_MODIFY←FALSE;
			NUM_OF_ERRORS_MODIFIED←NUM_OF_ERRORS_MODIFIED+1;
			β
		  ELSE  IF CAN_MODIFY
			THEN OUTSTR(" Global Modify - ****** Sorry, only local modify using M "&CRLF)
			ELSE OUTSTR(" Modify - ******** - sorry, non-modifiable error"&CRLF);

	["?"]	IF ¬TERSE THEN
		α
		OUTSTR("Reply [CR] or ""C"" to continue," & crlf &
		"[LF] or ""A"" to continue automatically," & crlf &
		"""E"" to edit source file," & crlf &
		"""R"" to restart," & crlf &
		"""T"" for terse," & crlf &
		"""V"" for verbose," & crlf &
		"""X"" to exit");
		IFC DEBUG_COMPILE THENC OUTSTR("," & crlf & """B"" to load Bail"); ENDC
		IF ¬LOGGING THEN OUTSTR("," & crlf & """L"" for logging");
		IF CAN_MODIFY THEN OUTSTR("," & crlf & """M"" for modify");
		IF BACKUP_MODIFY THEN OUTSTR(","&crlf& """G"" for backup and modify");
		IF PATCH_CODE THEN OUTSTR(","&crlf&"""P"" for patching source code");
		OUTSTR("." & crlf);
		β
		ELSE OUTSTR("OPTIONS cr,lf,E,R,T,X,B,L,M,G, and V? for verbose"&CRLF);

	["L"]	IF ¬LOGGING THEN
			α
			OPEN_LOGGING_FILE;
			OUT(CHANLOG,crlf & "ERROR TYPE " & CVS(I) & crlf & S & crlf
				& source_pos & crlf & LINE[1 TO L2] & lf & LINER & crlf);
			OUTSTR("ogging in file name " & LOGFILE & crlf );
			β
		  ELSE OUTSTR("ogging already");

	ELSE OUTSTR(" Unrecognized character; type ""?"" for allowable characters."&crlf)

		β;
	β;
IF I>0 THEN NUM_OF_ERRORS←NUM_OF_ERRORS+1;
RETURN(C1);
β;

RPTR(ANY_CLASS) PROCEDURE ERROR_REJECT(INTEGER I;STRING S);
    α  RPTR (ANY_CLASS)R1; R1←ERROR(I,S); REJECT←TRUE; RETURN(R1); β;

PROCEDURE PRINT(STRING S);
    α
    ifc debug_compile thenc
    INTEGER I,J,K,L;
    FOR I←1 STEP 1 UNTIL SPACING DO S←"  "&S;
    J←LENGTH(S);
    WHILE J>80 DO
	α;
	K←80;
	WHILE K≤J AND ¬EQU(S[K TO K]," ") DO K←K+1;
	OUT(CHANOUT,S[1 TO K] & crlf);
	S←S[K+1 TO J];
	J←J-K;
	β;
    OUT(CHANOUT,S & crlf)
    elsec
    INTEGER I;
    FOR I←1 STEP 1 UNTIL SPACING DO	OUT(CHANOUT,"  ");
    OUT(CHANOUT,S & crlf);
    endc;
    β;

procedure file_indent(integer i);
    α
    typed_page_num ← false;
    outstr("                                                         "[1 for 2*i]);
    β;

PROCEDURE UNDEFINED_VAR(STRING VAR(NULL));
	ERROR(0,"UNDEFINED VARIABLE   "&VAR);

PROCEDURE UNAFFIXED_VAR(STRING VAR(NULL));
	ERROR(0,"UNAFFIXED VARIABLE   "&VAR);
! process_switches, got_input, got_output, open_logging_file, open_new_file,check_want_copy;

    procedure process_switches(RPTR(file) F);
	α RPTR(file_switch) swt;
	swt ← file:switches[F];
	while swt≠null_record do
	    α integer i;
	    for i ← 0 step 1 until switch_max do
		if equ(file_switch:name[swt], switch_name[i])
		    then α switch_setting[i] ← true; done β;
	    if i > switch_max then
		outstr("""" & file_switch:name[swt] & """ unknown switch"& crlf);
	    swt ← file_switch:next[swt]
	    β
	β;

    boolean procedure got_input(RPTR(file) F);
	α
	if file:chn[F] < 0 then file:chn[F] ← getchan;
	if file:in_bfrs[F]≤0 then file:in_bfrs[F]←12;
	open(file:chn[F], file:device[F], file:mode[F], file:in_bfrs[F],
		file:out_bfrs[F], count, brchar, eof);
	if eof then
	    α release(file:chn[F]); file:chn[F] ← -1; return(false) β;
	infile ← make_file_name(F);
	lookup(file:chn[F], infile, eof);
	if eof ∧ length(file:ext[F])=0 ∧ length(file:def_ext[f])≠0 then
	    α "try default"
	    file:ext[F] ← file:def_ext[F];
	    infile ← make_file_name(F);
	    lookup(file:chn[F], infile, eof);
	    β "try default";
	process_switches(F);
	return(¬eof)
	β;

    boolean procedure got_output(RPTR(file) F);
	α
	string filename;
	if file:chn[F] < 0 then file:chn[F] ← getchan;
	open(file:chn[F], file:device[F], file:mode[F], file:in_bfrs[F],
	    file:out_bfrs[F], count, brchar, eof);
	if eof then
	    α release(file:chn[F]); file:chn[F] ← -1; return(false) β;
	if length(file:ext[F])=0 then file:ext[F] ← file:def_ext[F];
	filename ← make_file_name(F);
	enter(file:chn[F], filename, file:eof[F]);  process_switches(F);
	return(¬eof)
	β;

    procedure open_logging_file;
	if ¬log_file_open then
	α;
	LOG_file←new_record(file);
	copy_file_record(LOG_file,BIN_file);
	file:mode[LOG_file]←0; file:in_bfrs[LOG_file]← 0;
	file:out_bfrs[LOG_file]←12; file:ext[LOG_file] ← "LOG";
	file:device[LOG_file]← "DSK";
	file:name[LOG_file]←file:name[AL_file];
	if ¬got_output(LOG_file) then
	   usererr(0, 1, "can't get output");
	CHANLOG ← file:chn[LOG_file];
	LOGFILE←make_file_name(LOG_file);
	log_file_open←true;
	logging←true;
	β;

RPTR (file) procedure open_new_file(reference string s);
    begin string word;
    integer ignore_blanks_break,file_name_break,ppn_break,break;
    RPTR(file)F;
    integer procedure ignore_blanks(reference string s);
	begin integer break; scan(s, ignore_blanks_break, break); return(break) end;

    string procedure filwrd;
	begin ignore_blanks(s); return(scan(s, file_name_break, break)) end;

								setbreak(
ignore_blanks_break ← getbreak,	space & tab, cr, "XRK");
								setbreak(
file_name_break ← getbreak,	"[:.," & lf, cr, "ISK");
								setbreak(
ppn_break ← getbreak,		"]" & lf, cr, "ISK");
    F←new_record(file);
    word ← filwrd;  file:chn[F] ← -1;	! file has not been opened flag;
    if break=":" then begin file:device[F] ← word; word ← filwrd end;
    file:name[F] ← word;
    if break="." then file:ext[F] ← filwrd;
    if break="[" then
	begin
	ignore_blanks(s); file:ppn[F] ← "[" & scan(s, ppn_break, break) & "]";
	if break="]" then begin ignore_blanks(s); break ← lop(s) end;
	end;
    if length(file:device[F])=0 then file:device[F] ← "DSK";
    return(F);
    end;

PROCEDURE CHECK_WANT_COPY;
	  IF ¬EQU(FILE:NAME[PRESENT_FILE],NULL)
	    THEN
	    α	STRING SAVE;
		!   OUTSTR(CRLF&"Teletype input requested.  Want to save on disk?(Y or N)");
		! ALTERNATIVE METHOD  SAVE←INCHRW;
		SAVE←"Y";
	    IF SAVE = "Y" 
	      THEN
	      α RPTR(FILE)F;
	      F←NEW_RECORD(FILE);
	      copy_file_RECORD(F,PRESENT_FILE);
	      file:mode[F]←0;file:in_bfrs[F]←0;
	      file:out_bfrs[F]←12; if file:ext[F]=null then file:ext[f]←"TTY";
	      file:chn[f]←-1;
	      FILE:DEVICE[F]←"DSK";
	      IF ¬GOT_OUTPUT(F) THEN USERERR(0,1,"Can't get output");
	      CHANTTYO←FILE:CHN[F];
	      β
	      ELSE CHANTTYO←-1;
	    β ELSE CHANTTYO←-1;
! push_source_list,pop_source_list;

RPTR(SOURCE_LIST) PROCEDURE PUSH_SOURCE_LIST(RPTR(SOURCE_LIST)S1);
α
RPTR(SOURCE_LIST) S;
S←NEW_RECORD(SOURCE_LIST);
SOURCE_LIST:NEXT[S]←S1;
SOURCE_LIST:CUR_STRING[S]←CURLINE;
SOURCE_LIST:CUR_STRINGR[S]←TOKEN_FRONT&CURLINER;
SOURCE_LIST:PN[S]←PAGENUM;
SOURCE_LIST:LN[S]←LINENUM;
SOURCE_LIST:CHAN[S]←CHANIN;
SOURCE_LIST:FILE_NAME[S]←INFILE;
SOURCE_LIST:FILE_PTR[S]←PRESENT_FILE;
SOURCE_LIST:CHANTTYO[S]←CHANTTYO;
CHANTTYO←-1;
CURLINE←CURLINER←NULL;
RETURN(S);
β;

RPTR(SOURCE_LIST) PROCEDURE POP_SOURCE_LIST(RPTR(SOURCE_LIST)S1);
α
CURLINE←SOURCE_LIST:CUR_STRING[S1];
CURLINER←SOURCE_LIST:CUR_STRINGR[S1];
PAGENUM←SOURCE_LIST:PN[S1];
LINENUM←SOURCE_LIST:LN[S1];
CHANIN←SOURCE_LIST:CHAN[S1];
PRESENT_FILE←SOURCE_LIST:FILE_PTR[S1];
INFILE←SOURCE_LIST:FILE_NAME[S1];
CHANTTYO←SOURCE_LIST:CHANTTYO[S1];
RETURN(SOURCE_LIST:NEXT[S1]);
β;
! id info processing routines;

!	FLAGS
	BIT	35	USE
		34	DEFINE
		33	AFFIX
		0-9	PAGENUM
		10-19	LINENUM   ;

DEFINE RID1=[RPTR(ID_LIST)R1];

 BOOLEAN PROCEDURE USED(RID1);
	RETURN(ID_LIST:FLAGS[R1] LAND '1);

 BOOLEAN PROCEDURE DEFINED(RID1);
	RETURN(ID_LIST:FLAGS[R1] LAND '2);

 BOOLEAN PROCEDURE AFFIXED(RID1);
	RETURN(ID_LIST:FLAGS[R1] LAND '4);

 PROCEDURE USE(RID1);
	ID_LIST:FLAGS[R1]←ID_LIST:FLAGS[R1] LOR '1;

 PROCEDURE DEFIN(RID1);
	ID_LIST:FLAGS[R1]←ID_LIST:FLAGS[R1] LOR '2;

 PROCEDURE AFFIX(RID1);
	ID_LIST:FLAGS[R1]←ID_LIST:FLAGS[R1] LOR '4;

 PROCEDURE UNFIX(RID1);
	ID_LIST:FLAGS[R1]←ID_LIST:FLAGS[R1] LAND '777777777773;

 PROCEDURE PUT_ID_PAGE(RID1);
	ID_LIST:FLAGS[R1]←(((ID_LIST:FLAGS[R1] ROT 10)LAND '777777776000)+PAGENUM+1) ROT -10;

 PROCEDURE PUT_ID_LINE(RID1);
	ID_LIST:FLAGS[R1]←(((ID_LIST:FLAGS[R1] ROT 20)LAND '777777776000)+LINENUM+1) ROT -20;

 INTEGER PROCEDURE ID_PAGE(RID1);
	RETURN((ID_LIST:FLAGS[R1] ROT 10)LAND '1777);

 INTEGER PROCEDURE ID_LINE(RID1);
	RETURN((ID_LIST:FLAGS[R1] ROT 20)LAND '1777);

! read, push_macro_delimiters;


STRING PROCEDURE READ(INTEGER BTABLE);
	! RIGHT NOW THIS PROCEDURE IS KIND OF DUMB.  IT'S INCLUDED IN THE HOPE
	  OF EVENTUALLY MAKING THE READING FACILITY MORE VERSATILE;
α STRING TEXT;
text ← SCAN(CURLINER,BTABLE,BRCHAR);
WHILE BRCHAR=0 DO
	α BOOLEAN REPLACED;
	REPLACED←TRUE;
	IF CHANIN>-1 THEN α  STRING CURR;
		CURLINE←CURLINER←INPUT(CHANIN,lf_ff_break);
		IF CHANTTYO≥0 THEN OUT(CHANTTYO, CURLINE);
		CURR←CURLINE[1 TO (LENGTH(CURLINE)-2)]&" ";
		ERROR_BUFFER←ERROR_BUFFER&CURR;
		BACKUP_ERROR_BUFFER←BACKUP_ERROR_BUFFER&CURR;
		macro_stack_top←macro_st2; macro_st2←null_record;β;
	
	IF CHANIN≤-1 THEN
		α "pop macro"
		CHANIN←SOURCE_LIST:CHAN[TOP_SOURCE];
		CURLINE←SOURCE_LIST:CUR_STRING[TOP_SOURCE];
		CURLINER←" "&SOURCE_LIST:CUR_STRINGR[TOP_SOURCE];
		PAGENUM←SOURCE_LIST:PN[TOP_SOURCE];
		LINENUM←SOURCE_LIST:LN[TOP_SOURCE];
		macro_st2←SOURCE_LIST:macro_stack_TOP[TOP_SOURCE];
		CURRENT_MACRO←SOURCE_LIST:CUR_MACRO[TOP_SOURCE];
		TOP_SOURCE←SOURCE_LIST:NEXT[TOP_SOURCE];
		β "pop macro"
	ELSE IF BRCHAR=lf THEN LINENUM←LINENUM+1
	ELSE IF BRCHAR=ff THEN 
		α
		outstr(" " & cvs((PAGENUM←PAGENUM+1)+1));
		typed_page_num ← true;  LINENUM←0
		β
	ELSE IF TOP_SOURCE≠NULL THEN
		α "close_source"
		RELEASE(CHANIN);
		IF EQU(FILE:DEVICE[PRESENT_FILE],"TTY") THEN RELEASE(CHANTTYO);
		CURRENT_MACRO←NULL_RECORD;
		MAC_NUM←SOURCE_LIST:NUM[TOP_SOURCE];
		TOP_SOURCE←POP_SOURCE_LIST(TOP_SOURCE);
		outstr(crlf);  typed_page_num ← false;  sourcelvl ← sourcelvl-1;
		β "close_source"
	ELSE IF EOF THEN ERROR(500,"end of file encountered unexpectedly.");
	TEXT ← TEXT & SCAN(CURLINER,BTABLE,BRCHAR);
	β;
RETURN(TEXT);
β;

procedure push_delimiters(string s);
    α RPTR(delimiter_list) new_del;
    DELIMITER_LIST:NEXT[NEW_DEL ← new_record(delimiter_list)] ← TOP_DELIMITERS;
    DELIMITER_LIST:D1[NEW_DEL] ← lop(s);  DELIMITER_LIST:D2[NEW_DEL] ← lop(s);
    TOP_DELIMITERS←NEW_DEL;
    β;
! macro handling routine;

BOOLEAN procedure macro_handler;
    α "macro_handler"
    INTEGER HASH_ENTRY; STRING MACRO_NAME;
    INTEGER PARAM_COUNT;
    BOOLEAN SPECIAL_DELIMS; RPTR (MACRO_LIST) MAC_POINT;
    RPTR (PARAM_LIST) TOP_PARAM, NEW_PARAM, LAST_PARAM;
    BOOLEAN STATUS;
    LABEL FLUSH;

	PROCEDURE F_STATE(VALUE INTEGER PP,IP; VALUE STRING SP);
	α STRING CLOSE; INTEGER I;
	FOR I←1 STEP 1 UNTIL PP DO CLOSE←CLOSE&")";
	SPACING←SPACING-PP;
	PRINT(CLOSE);
	ERROR(IP,SP&crlf&"Continue will flush statement.");
	WHILE ¬EQU(TOKEN,";") DO GET_TOKEN;
	REJECT←TRUE;
	STATUS←FALSE;
	NUM_OF_ERRORS_FLUSHED←NUM_OF_ERRORS_FLUSHED+1;
	GOTO FLUSH;
	β;

    procedure macro_delimiters(boolean turn_on);
	α string chr1, chr2;
	if turn_on
	    then if top_delimiters≠null_record
		then
		    α
		    chr1 ← delimiter_list:d1[top_delimiters];
		    chr2 ← delimiter_list:d2[top_delimiters];
		    β
		else chr1 ← chr2 ← dquote
	    else chr1 ← chr2 ← null;
	delimiter_1 ← chr1;  delimiter_2 ← chr2;
	SETBREAK(macro_delimiter_break, chr1 & chr2, NULL, "ISN");
	SETBREAK(word_R_break, TABLE1 & chr1, NULL, "INRK");
	SETBREAK(word_S_break, TABLE1 & chr1, NULL, "INSK");
	β;

    STATUS←TRUE;
    do  α "define_macro"
	INSIDE_MACRO_DEFINITION←TRUE;
	SPECIAL_DELIMS←FALSE;  PARAM_COUNT←0;  GET_TOKEN;
	INSIDE_MACRO_DEFINITION←FALSE;
	IF TYPE_OF_TOKEN≠undeclared_token and SPECIAL_INFO=BLOCK_LEVEL
	    THEN F_STATE(0,56,"Can only define unreserved ID's.");
	MACRO_NAME←TOKEN;  GET_TOKEN;
	IF EQU(TOKEN,"(") THEN
		α "macro_parameters"
		TOP_PARAM←LAST_PARAM←NEW_RECORD(PARAM_LIST);
		WHILE ¬EQU(TOKEN,")") DO
			α
			GET_TOKEN;
			IF TYPE_OF_TOKEN≠undeclared_token
			    THEN F_STATE(0,57,"Can only use unreserved ID's as parameter names.");
			PARAM_COUNT←PARAM_COUNT+1; NEW_PARAM←NEW_RECORD(PARAM_LIST);
			PARAM_LIST:NEXT[LAST_PARAM]←NEW_PARAM;
			PARAM_LIST:USER_ID[NEW_PARAM]←TOKEN;  LAST_PARAM←NEW_PARAM;
			GET_TOKEN;
			IF ¬EQU(TOKEN,")") AND ¬EQU(TOKEN,",") THEN
				α
				ERROR(58,"Need either comma or right paren here.");
				REJECT←TRUE;  TOKEN←")";
				β;
			β;
		TOP_PARAM←PARAM_LIST:NEXT[TOP_PARAM];
		GET_TOKEN;
		β "macro_parameters"
		ELSE TOP_PARAM←LAST_PARAM←NULL_RECORD;
	IF TYPE_OF_TOKEN=string_token THEN
		α "special_delimiters"  RPTR (DELIMITER_LIST) NEW_DEL;
		SPECIAL_DELIMS←TRUE;
		IF TYPE_OF_TOKEN≠string_token THEN F_STATE(0,52,"Need string here.");
		IF LENGTH(TOKEN)≠2 THEN F_STATE(0,53,"Need string of length 2.");
		push_delimiters(token);
		get_token;
		β "special_delimiters";
	IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(59,"Need = here.");
	macro_delimiters(true);  GET_TOKEN;

	IF TYPE_OF_TOKEN≠macro_body_token THEN F_STATE(0,60,"Need string here.")
	ELSE
	α
	! bind macros;
	if param_count>0 then
		α "PARAMS"
		string array param_id, param_arg[1:param_count];
		integer i,width,digits;
		string t1;
		string t, processed_token;
		STRING BREAK_STRING;
		string t2;
		RPTR(param_list) param_ptr;
		param_ptr←top_param;
		BREAK_STRING←NULL;
		GETFORMAT(WIDTH,DIGITS);
		SETFORMAT(-2,0);
		if chanin>0 then t1←"00" else t1←cvs(abs(chanin));
		for i ← 1 step 1 until param_count do
			α
			param_id[i]←param_list:user_id[param_ptr];
			param_arg[i]←(param_list:id[param_ptr]← "∀∀∀∀__"& t1 & "__"&cvs(i));
			param_ptr←param_list:next[param_ptr];
			β;

		SETFORMAT(WIDTH,DIGITS);
		processed_token← NULL;
		SETBREAK(word_S_break, TABLE1 & delimiter_1 & delimiter_2, NULL, "INSK");
		do α
		integer brchar,brchar2;
		t2←scan(token,non_blank_break,brchar);
		if t2≠null then processed_token←processed_token&t2;
		t←scan(token,word_s_break,brchar2);
		if t≠null then
			α for i←1 step 1 until param_count do
			if equ(t,param_id[i]) then t←param_arg[i];
			processed_token←processed_token&t;
			β;
		if brchar2≠null then processed_token←processed_token&brchar2;
		β until length(token)=0;
		token←processed_token;
		β "PARAMS";

	! done binding macros;
	β;

	macro_delimiters(false);

	if chanin≤-1
		then mac_point←insert_entry(macro_name,macro_in_macro_type_table)
		else mac_point←insert_entry(macro_name,macro_type_table);
	MACRO_LIST:VALUE[MAC_POINT]←TOKEN;
	MACRO_LIST:NUM[MAC_POINT]←PARAM_COUNT;
	MACRO_LIST:PARAMS[MAC_POINT]←TOP_PARAM;
	MACRO_LIST:BLOCK_LEVEL_OF_DEFN[MAC_POINT]←BLOCK_LEVEL;
	IF top_delimiters≠null then
		MACRO_LIST:DELIMITERS[MAC_POINT]←delimiter_list:d1[top_delimiters]
				& delimiter_list:d2[top_delimiters];

	IF SPECIAL_DELIMS THEN
		α
		IF NULL=TOP_DELIMITERS
		    THEN F_STATE(0,54,"Can't unstack special delimiters!");
		TOP_DELIMITERS←DELIMITER_LIST:NEXT[TOP_DELIMITERS];
		β;
	get_token;
	β "define_macro"
    until ¬equ(token, ",");
    if equ(token, ";") then reject ← true;
FLUSH: RETURN(STATUS);

    β "macro_handler";
! expand_macro;

RECURSIVE PROCEDURE EXPAND_MACRO;
α 	RPTR(macro_list) m1;
RPTR(MACRO_CONCATENATE_LIST) C1;
STRING PROCESSED_BODY,D1,D2;
RPTR(SOURCE_LIST)NEW_SOURCE2;
PROCESSED_BODY←NULL;
	NEW_SOURCE2←NEW_RECORD(SOURCE_LIST);
	SOURCE_LIST:CHAN[NEW_SOURCE2]←CHANIN;
	SOURCE_LIST:CUR_MACRO[NEW_SOURCE2]←CURRENT_MACRO;
CURRENT_MACRO←CUR_MACRO;
c1←MACRO_CON_HEAD;
do	α "expand macro"
	STRING MAC_ID; RPTR(PARAM_LIST) PARAMS;
	STRING BODY;
	INTEGER BRCHAR2;
	M1←MACRO_CONCATENATE_LIST:MACRO_PTR[C1];
	PARAMS←MACRO_LIST:PARAMS[M1];
	MAC_ID←MACRO_LIST:ID[M1];
	D1←MACRO_LIST:DELIMITERS[M1][1 FOR 1];
	D2←MACRO_LIST:DELIMITERS[M1][2 FOR 1];
	read(non_blank_break); token←read(word_R_break);
		if token=null then token←read(word_s_break);
	IF ¬EQU(TOKEN,"(") AND PARAMS≠NULL
	    THEN ERROR(59,"Parametered macro used without params.")
	    ELSE IF ¬EQU(TOKEN,"(")
	      THEN 
		α
		IF TOKEN= NULL THEN CURLINER←BRCHAR&CURLINER ELSE
		CURLINER←TOKEN&CURLINER;
		BODY←MACRO_LIST:VALUE[M1];
		β
	      ELSE
		α "macro parameters" 
		STRING T,t2r,t3;
		FOR I←1 STEP 1 UNTIL MACRO_LIST:NUM[M1] DO
		    α RPTR(MACRO_LIST)SUB_MACRO;
		    IF EQU(TOKEN,")") THEN
			ERROR(60,"Number of parameters disagree with definition.");
		    GET_TOKEN;
!		    IF TYPE_OF_TOKEN≠string_token THEN
			ERROR(61,"Need a string here.");
		    SUB_MACRO←INSERT_ENTRY(PARAM_LIST:ID[PARAMS],MACRO_IN_MACRO_TYPE_TABLE);
		    MACRO_LIST:VALUE[SUB_MACRO]←TOKEN;
		    GET_TOKEN;
		    IF ¬EQU(TOKEN,",") AND ¬EQU(TOKEN,")") THEN 
			ERROR_REJECT(62,"NEED EITHER COMMA OR RIGHT PAREN HERE.");
		    PARAMS←PARAM_LIST:NEXT[PARAMS];
		    β;
		IF ¬EQU(TOKEN,")") THEN ERROR(62,"Number of parameters don't match the defn.");
		body←macro_list:value[m1];
		β "macro parameters";
	PROCESSED_BODY←processed_body&body;
	β "expand macro" until (c1←macro_concatenate_list:next[c1])=NULL_record;


	SOURCE_LIST:NUM[NEW_SOURCE2]←MACRO_LIST:NUM[M1];
	SOURCE_LIST:NEXT[NEW_SOURCE2]←TOP_SOURCE;
	SOURCE_LIST:CUR_STRING[NEW_SOURCE2]←CURLINE;
	SOURCE_LIST:CUR_STRINGR[NEW_SOURCE2]←CURLINER;
	SOURCE_LIST:PN[NEW_SOURCE2]←PAGENUM;
	SOURCE_LIST:LN[NEW_SOURCE2]←LINENUM;
	SOURCE_LIST:MACRO_STACK_TOP[NEW_SOURCE2]←MACRO_STACK_TOP;
	SOURCE_LIST:MACRO_STRING[NEW_SOURCE2]←MACRO_STRING;
	SOURCE_LIST:FILE_PTR[NEW_SOURCE2]←PRESENT_FILE;
	IF CHANIN≥0 THEN CHANIN←-1 ELSE CHANIN←CHANIN-1;
	MACRO_STRING←processed_body;
	CURLINE←CURLINER←processed_body;
	TOP_SOURCE←NEW_SOURCE2;
	GET_TOKEN;
	WHILE EQU(TOKEN,"DEFINE") DO 
		α 
		macro_handler; get_token; GET_TOKEN; 
		β;
β;	
! get_token;

! THIS PROCEDURE GETS THE NEXT TOKEN.  
	STRING	TOKEN ← TOKEN FOUND
	INTEGER	TYPE_OF_TOKEN← SPECIAL_TOKEN, NUMERIC_TOKEN, STRING_TOKEN, ID_TOKEN,
		MACRO_TOKEN, METRIC_TOKEN, UNDEFINED_TOKEN, RESERVED_TOKEN
	INTEGER	TYPE_OF_RES_WORD ← -VE IF NOT RESERVED WORD
	INTEGER ID_TYPE ← VALID FOR TYPE_OF_TOKEN=ID_TOKEN
	INTEGER	SPECIAL_INFO ← PERTAINS TO INFO ABOUT RES_WORD
	INTEGER BLOCK_LEVEL_OF_DEFN ← PERTAINS TO BLOCK LEVEL OF DEFN
	INTEGER RESERVED_TOKEN_PTR← POINTER TO POSITION IN RESERVED,COM[0:RESERVED_HASHER]
	REAL REALNUM← REAL NUMBER FOUND
	RPTR	TOKEN_PTR← GENERAL POINTER TO TOKEN FOUND AS ID, ETC;

RECURSIVE PROCEDURE GET_TOKEN;
α "get_token"  BOOLEAN T;  INTEGER POINT;

RECORD_POINTER(MACRO_LIST) PROCEDURE LOOK_FOR_MACRO;
α RECORD_POINTER (MACRO_LIST) R1;
	IF MACRO_STACK_TOP≠NULL
	    THEN R1←CHECK_ENTRY(TOKEN,MACRO_IN_MACRO_TYPE_TABLE);
	IF R1=NULL 
	    THEN R1←CHECK_ENTRY(TOKEN,MACRO_TYPE_TABLE);
RETURN(R1);
β;

! IF REJECT THEN α REJECT←FALSE;  ! ************ ; ! RETURN; ! ************; ! β;
IF REJECT THEN α CURLINER←TOKEN&CURLINER; REJECT←FALSE; β;

BLOCK_LEVEL_OF_DEFN←RESERVED_TOKEN_PTR←
ID_TYPE←TYPE_OF_RES_WORD←SPECIAL_INFO←-100;
TOKEN_PTR←NULL_RECORD;
TYPE_OF_TOKEN←special_token;  T←TRUE;
WHILE T DO
  α "while_T"
  TOKEN_FRONT←READ(non_blank_break);  TOKEN←READ(word_R_break);
  IF EQU(TOKEN,NULL) 
    THEN
	α "isolated break"
	CASE BRCHAR OF
	α

	["."]	
		α REAL NUM; STRING S1; S1←CURLINER[2 FOR 1];
		  IF "0"≤S1≤"9"
		    THEN α NUM←REALSCAN(CURLINER,BRCHAR);
		      TYPE_OF_TOKEN←numeric_token; REALNUM←NUM; TOKEN←CVG(NUM) β
		    ELSE α TOKEN←"."; CURLINER←CURLINER[2 TO ∞]; β;
	        β;
	ELSE	;

	[SQUOTE]
		α REAL NUM; garb←LOP(CURLINER);
		  IF "0"≤CURLINER[2 FOR 1]≤"7"
		    THEN α TYPE_OF_TOKEN←numeric_token; REALNUM←NUM;
		          TOKEN←CVS(NUM); REALNUM←CVO(TOKEN); β
		    ELSE TOKEN←squote;
		β
	β;
    IF EQU(TOKEN,NULL) THEN α READ(word_S_break); TOKEN←BRCHAR; β;
   β "isolated break";
  IF EQU(TOKEN,OPEN_BRACE) THEN TOKEN←READ(close_brace_break) ELSE T←FALSE;
  β "while_T";

! delimiter_1 non-zero only while defining macro;

if delimiter_1 and token=delimiter_1
  then
  α "found_macro_body" integer lvl;
  token←read(macro_delimiter_break); type_of_token ← macro_body_token;
  if delimiter_1=delimiter_2 ∨ brchar=delimiter_2 then return; ! ******** ;
  lvl ← 2; if brchar≠delimiter_1 then error(200, "macro body scan lost");
  do 
    α token ← token & brchar & read(macro_delimiter_break);
    if brchar=delimiter_2
      then lvl ← lvl-1
      else if brchar=delimiter_1
	then lvl ← lvl+1
	else error(200, "macro body scan lost");
    β
  until lvl ≤ 0;
  return; ! ************* ;
  β "found_macro_body";

IF TOKEN=dquote 
  THEN
  α "found_string"
  TOKEN←READ(quote_break); TYPE_OF_TOKEN←string_token;
  while curliner=dquote do token ← token & lop(curliner) & read(quote_break);
! ********* ;	RETURN; ! ********** ;
  β "found_string";

!	look for reserved word;

IF TYPE_OF_TOKEN=special_token
  THEN
  α POINT←HASH(TOKEN,reserved_hasher);
    WHILE ¬EQU(RESERVED[POINT],NULL) AND ¬EQU(RESERVED[POINT],TOKEN) DO
		POINT←(POINT+1)MOD reserved_hasher;
    IF RESERVED[POINT]=TOKEN
    THEN
    α "reserved word" INTEGER VAL; TYPE_OF_TOKEN←reserved_token; VAL←COM_TYPE[POINT];
    RESERVED_TOKEN_PTR←POINT;
    IF VAL≥reserved_hasher
      THEN α SPECIAL_INFO←(VAL DIV reserved_hasher); TYPE_OF_RES_WORD←(VAL MOD reserved_hasher); β
      ELSE α SPECIAL_INFO←0;  TYPE_OF_RES_WORD←VAL;  β;
    β "reserved word";
    α "not reserved"
    RECORD_POINTER(ANY_CLASS)POINT,POINT2;
    IF ¬("0" ≤ token ≤ "9")
      THEN 
      α "MAC_TEST"
      IF (TOKEN_PTR←CHECK_ENTRY(TOKEN,ID_TYPE_TABLE))≠NULL_RECORD 
	THEN α TYPE_OF_TOKEN←ID_TOKEN; BLOCK_LEVEL_OF_DEFN←ID_LIST:BLOCK_LEVEL_OF_DEFN[TOKEN_PTR]; β;
      IF (POINT2←CHECK_ENTRY(TOKEN,DIMENSION_TYPE_TABLE))≠NULL_RECORD 
	THEN 
	α IF TOKEN_PTR=NULL_RECORD 
	  THEN α TOKEN_PTR←POINT2; TYPE_OF_TOKEN←METRIC_TOKEN;β
	  ELSE IF DIMENS_EXPONENT:BLOCK_LEVEL_OF_DEFN[POINT2] > BLOCK_LEVEL_OF_DEFN
	    THEN α TYPE_OF_TOKEN←METRIC_TOKEN; TOKEN_PTR←POINT2;
			BLOCK_LEVEL_OF_DEFN←DIMENS_EXPONENT:BLOCK_LEVEL_OF_DEFN[TOKEN_PTR]; β;
	β;
      IF (CUR_MACRO←LOOK_FOR_MACRO)≠NULL_RECORD
	THEN IF TOKEN_PTR=NULL_RECORD OR MACRO_LIST:BLOCK_LEVEL_OF_DEFN[CUR_MACRO]>
			BLOCK_LEVEL_OF_DEFN
	  THEN
	  α "MACRO"
	  string ttoken; record_pointer (macro_concatenate_list) ptr;
	  record_pointer(macro_list)r1;
	  BLOCK_LEVEL_OF_DEFN←MACRO_LIST:BLOCK_LEVEL_OF_DEFN[CUR_MACRO];
	  PTR←(MACRO_CON_HEAD←NEW_RECORD(MACRO_CONCATENATE_LIST));
	  macro_concatenate_list:macro_ptr[ptr]←cur_macro;
	  read(non_blank_break); ttoken←read(word_R_break);
	  while ttoken= null and brchar="&"
	  do α
	     curliner←curliner[2 to ∞]; read(non_blank_break);
	     token←read(word_S_break);
	     if (r1←look_for_macro) = null 
	       then 
	       α error(1111, "Need macro name here.");
	       curliner←token&brchar&curliner;
	       β
	       else
	       α ptr←(macro_concatenate_list:next[ptr]←new_record(macro_concatenate_list));
	       macro_concatenate_list:macro_ptr[ptr]←r1;
	       read(non_blank_break);ttoken←read(word_r_break);
	       β;
	    β;
	  curliner←ttoken&curliner;
	  EXPAND_MACRO;
	  β "MACRO";
      β "MAC_TEST"
      ELSE
      α "numeric" REAL NUM1,NUM2;  INTEGER NUMGARB;
      TYPE_OF_TOKEN←numeric_token; NUM1←INTSCAN(TOKEN,NUMGARB);
      IF ¬EQU(TOKEN,NULL) THEN ERROR(0,"Illegal token." & crlf & "Garbage after digits will be ignored.");
      IF BRCHAR="."
	THEN
	α CURLINER←"0"&CURLINER; NUM2←REALSCAN(CURLINER,BRCHAR);
	TOKEN←CVG(NUM1+NUM2);
	REALNUM←NUM1+NUM2;
	β
	ELSE IF BRCHAR="@"
	  THEN
	  α CURLINER←"1"&CURLINER; NUM2←REALSCAN(CURLINER,BRCHAR);
	  TOKEN←CVG(NUM1*NUM2);
	  REALNUM←NUM1*NUM2;
	  β
	  ELSE α TOKEN←CVG(NUM1); REALNUM←NUM1; β;
      β "numeric";
    β "not reserved";
  β;
  if type_of_token=id_token 
    then α if ¬inside_declare_p then use(token_ptr);
     if id_list:type[token_ptr]=string_value
      then if inside_string_declaration
	then id_type←string_value
	else α type_of_token←string_token; token←id_list:body[token_ptr]; token_ptr←null_record; β
      else id_type←id_list:type[token_ptr];
      β
    else if type_of_token=special_token then type_of_token←undeclared_token;
β "get_token";


! check_token,check_token_type;

boolean procedure check_next_token(integer err_code; string err_mess,
		s1,s2(null),s3(null),s4(null),s5(null),s6(null),
		s7(null),s8(null),s9(null),s10(null));
α  string array s[1:10]; integer i1,j1;label l1,l2; string st;
s[1]←s1;s[2]←s2;s[3]←s3;s[4]←s4;s[5]←s5;s[6]←s6;s[7]←s7;s[8]←s8;s[9]←s9;s[10]←s10;
i1←0;st←null;
	while s[i1+1]≠null do α i1←i1+1;st←st & s[i1] & ","; β;

	if i1 > 1 then
	α
	l1:	get_token;
		for j1←1 step 1 until i1
			do if equ(token , s[j1]) then return(true);
		patch_code←true;
		error(err_code,err_mess&crlf&"Need one of "&st& " here, patchable error ");
		if patch_code=true
		  then	α patch_code←false; return(false); β
		  else  goto l1;
	β else
	α
	l2:	get_token;
		if equ(token,s1) then return(true);
		patch_code←true;
		error(err_code,err_mess&crlf&"Need "&s1&" here, continue will insert it.");
		if patch_code = true
		  then α patch_code←false; return(false); β
		  else goto l2;
	β;

β;

boolean procedure check_token(integer err_code; string err_mess,
		s1,s2(null),s3(null),s4(null),s5(null),s6(null),
		s7(null),s8(null),s9(null),s10(null));
α
reject←true;
return(check_next_token(err_code,err_mess,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10));
β;

boolean procedure check_next_token_type(integer err_code; string err_mess;
		integer ttype);
α	Label l1;
	get_token;
    l1:	if type_of_token=ttype then return(true);
	patch_code←true;
	error(err_code,err_mess);
	if patch_code=true then α patch_code←false; return(false); β
	  else goto l1;
β;

boolean procedure check_token_type(integer err_code; string err_mess;
		integer ttype);
α
reject←true;
return(check_next_token_type(err_code,err_mess,ttype));
β;

boolean procedure token_equ(string s1,s2(null),s3(null),s4(null),s5(null),
			s6(null),s7(null),s8(null),s9(null),s10(null));
α	string s;
	for s←s1,s2,s3,s4,s5,s6,s7,s8,s9,s10
		do if equ(null,s) then return(false)
			else if equ(token,s) then return(true);
	return(false);
β;
! check, inverse, multiply and divide dimensions; ! CHECK_EXP_TYPE_DIMENS;

RPTR(DIMENS_EXPONENT)
	PROCEDURE CHECK_DIMENSIONS(STRING S; RPTR(DIMENS_EXPONENT) D1,D2);
α RPTR(DIMENS_EXPONENT)II1,II2,II3;STRING SS;BOOLEAN SAME;
SS←NULL;
SAME←TRUE;
II1←D1;  II2←D2;
IF II1≠II2 THEN
	α IF II1=NULL_RECORD THEN II1←NIL_DIMENS;
	IF II2=NULL_RECORD THEN II2←NIL_DIMENS;
	redefine xx(temp)= [ IF DIMENS_EXPONENT:temp[II1]≠DIMENS_EXPONENT:temp
		[II2] THEN α IF LENGTH(SS)≠0 THEN SS←SS&", temp " ELSE SS←" temp ";
					SAME←FALSE;β;];
	IF ¬STRICT_DIMEN_CHECK OR ((II2≠NIL_DIMENS) AND (II1≠NIL_DIMENS))
	THEN α BASIC_DIMENSIONS;
	       IF SAME THEN II3←II1
	       ELSE ERROR(122, SS & "Dimensions don't match on "&S&".");
	     β
	ELSE IF II1≠NIL_DIMENS THEN II3←II1 ELSE II3←II2;
	β
	ELSE IF II1=NULL_RECORD THEN II3←NIL_DIMENS ELSE II3←II1;
IF SAME THEN RETURN(II3);
β;



RPTR(DIMENS_EXPONENT)
	PROCEDURE INVERSE_DIMENSIONS(RPTR(DIMENS_EXPONENT)D2);
α
RPTR(DIMENS_EXPONENT) D1;
IF D2≠NULL_RECORD THEN 
	α
	RPTR(DIMENS_EXPONENT) II2;
	D1←NEW_RECORD(DIMENS_EXPONENT);
	II2←D2;
	redefine xx(temp)=[DIMENS_EXPONENT:temp[D1]←-DIMENS_EXPONENT:temp[II2];];
	BASIC_DIMENSIONS;
	β
ELSE D1←NULL_RECORD;
RETURN(D1);
β;


RPTR(DIMENS_EXPONENT)
	 PROCEDURE MULTIPLY_DIMENSIONS(RPTR(DIMENS_EXPONENT)D2,D3);
α
RPTR(DIMENS_EXPONENT) D1;
IF D2=NULL_RECORD OR D3=NULL_RECORD THEN
	α
	IF D2≠NULL_RECORD THEN D1←D2
		ELSE IF D3≠NULL_RECORD THEN D1←D3;
	β
ELSE
	α
	RPTR(DIMENS_EXPONENT) II2,II3;
	D1←NEW_RECORD(DIMENS_EXPONENT);
	II2←D2;II3←D3;
	redefine xx(temp)=[DIMENS_EXPONENT:temp[D1]←DIMENS_EXPONENT:temp[II2]+
		DIMENS_EXPONENT:temp[II3];];
	BASIC_DIMENSIONS;
	β;
RETURN(D1);
β;



RPTR(DIMENS_EXPONENT)
	PROCEDURE DIVIDE_DIMENSIONS(RPTR(DIMENS_EXPONENT)D2,D3);
α
RPTR(DIMENS_EXPONENT) D1;
IF D2=NULL_RECORD OR D3=NULL_RECORD THEN
	α
	IF D2≠NULL_RECORD THEN D1←D2
		ELSE IF D3≠NULL_RECORD THEN D1←INVERSE_DIMENSIONS(D3);
	β
ELSE
	α
	RPTR(DIMENS_EXPONENT)II2,II3;
	D1←NEW_RECORD(DIMENS_EXPONENT);
	II2←D2;II3←D3;
	redefine xx(temp)=[DIMENS_EXPONENT:temp[D1]←DIMENS_EXPONENT:temp[II2]-
		DIMENS_EXPONENT:temp[II3];];
	BASIC_DIMENSIONS;
	β;
RETURN(D1);
β;

BOOLEAN PROCEDURE CHECK_EXP_TYPE_DIMENS(INTEGER DESIRED_EXP_TYPE;
		RPTR(DIMENS_EXPONENT) PTR;
		STRING ERROR_MESS);
α
	CHECK_DIMENSIONS(ERROR_MESS,PTR,EXP_DIMENS);
	IF EXP_TYPE=DESIRED_EXP_TYPE THEN RETURN (TRUE) ELSE RETURN (FALSE);
β;
! check_entry,insert_entry into tables;

RPTR (ANY_CLASS) PROCEDURE CHECK_ENTRY (STRING S; INTEGER TABLE_TYPE);
α
RPTR(ANY_CLASS)R1;
CASE TABLE_TYPE OF
	α
[ID_TYPE_TABLE]	α R1←SYMBOL_TABLE[HASH(S,ID_HASHER)];
		WHILE R1≠NULL AND ¬EQU(S,ID_LIST:NAME[R1]) DO R1←ID_LIST:NEXT[R1];
		β;

[MACRO_TYPE_TABLE]	α R1←MACRO_TABLE[HASH(S,MACRO_HASHER)];
		WHILE R1≠NULL AND  ¬EQU(S,MACRO_LIST:ID[R1]) DO R1←MACRO_LIST:NEXT[R1];
		β;

[MACRO_IN_MACRO_TYPE_TABLE]
		α R1←MACRO_STACK_TOP;
		WHILE R1≠NULL AND ¬EQU(S,MACRO_LIST:ID[MACRO_STACK:LIST_PTR[R1]])
			DO R1←MACRO_STACK:STACK_LINK[R1];
		IF R1≠NULL_RECORD THEN R1←MACRO_STACK:LIST_PTR[R1];
		β;

[DIMENSION_TYPE_TABLE]
		α R1←DIMENS_TABLE[HASH(S,METRIC_HASHER)];
		WHILE R1≠NULL AND ¬ EQU(S,DIMENS_EXPONENT:NAME[R1]) DO R1←DIMENS_EXPONENT:NEXT[R1];
		β
	β;
RETURN(R1);
β;

RPTR (ANY_CLASS) PROCEDURE INSERT_ENTRY (STRING S; INTEGER TABLE_TYPE;
RPTR(ANY_CLASS) RR1(NULL_RECORD));
α
RPTR(ANY_CLASS) R1; INTEGER INDEX;
CASE TABLE_TYPE OF
	α
[ID_TYPE_TABLE]	α
		IF RR1=NULL_RECORD THEN R1←NEW_RECORD(ID_LIST) ELSE R1←RR1;
		ID_LIST:NEXT[R1]←SYMBOL_TABLE[INDEX←HASH(S,ID_HASHER)];
		ID_LIST:NAME[R1]←S;
		SYMBOL_TABLE[INDEX]←R1;
		IF ¬INITIALIZE THEN
			α ID_LIST:LAST[R1]←TOP_ID;
			ID_LIST:BLOCK_LEVEL_OF_DEFN[R1]←BLOCK_LEVEL;
			PUT_ID_PAGE(R1); PUT_ID_LINE(R1);
			TOP_ID←R1;DEC_NUM←DEC_NUM+1; β;
		β;

[MACRO_TYPE_TABLE]	α
		IF RR1=NULL_RECORD THEN R1←NEW_RECORD(MACRO_LIST) ELSE R1←RR1;
		MACRO_LIST:NEXT[R1]←MACRO_TABLE[INDEX←HASH(S,MACRO_HASHER)];
		MACRO_LIST:ID[R1]←S;
		MACRO_TABLE[INDEX]←R1;
		IF ¬INITIALIZE THEN α MACRO_LIST:LAST[R1]←TOP_MACRO;
				TOP_MACRO←R1; MACRO_DEC_NUM←MACRO_DEC_NUM+1; β;
		β;

[MACRO_IN_MACRO_TYPE_TABLE]
		α
		RPTR (macro_list)r2;
		IF RR1=NULL_RECORD THEN R2←NEW_RECORD(MACRO_list) ELSE R2←RR1;
		r1←new_record(macro_stack);
		MACRO_STACK:STACK_LINK[R1]←macro_stack_top;
		macro_stack:list_ptr[r1]←r2;
		MACRO_STACK_TOP←R1;
		macro_list:id[r2]←s;
		R1←R2;
		β;

[DIMENSION_TYPE_TABLE]
		α
		IF RR1=NULL_RECORD THEN R1←NEW_RECORD(DIMENS_EXPONENT) ELSE R1←RR1;
		DIMENS_EXPONENT:NAME[R1]←S;
		DIMENS_EXPONENT:NEXT[R1]←DIMENS_TABLE[INDEX←HASH(S,METRIC_HASHER)];
		DIMENS_TABLE[INDEX]←R1;
		IF ¬INITIALIZE THEN α DIMENS_EXPONENT:LAST[R1]←TOP_DIMENS;
				TOP_DIMENS←R1; DIMEN_DEC_NUM←DIMEN_DEC_NUM+1; β;
		β
	β;
RETURN(R1);
β;
! reduce, fail_up,vmake_R,vv_trans_R;

PROCEDURE REDUCE;
	α INTEGER CUR_OP_NUM; LABEL RAISE;

	PROCEDURE FAIL_UP(INTEGER I; STRING S);
		α RPTR(EXPR)E;RPTR(EXPR_LIST)EL;
		ERROR(I,S&crlf&"I will reduce it to GARB_ID as default.");
		E←NEW_RECORD(EXPR);
		EL←NEW_RECORD(EXPR_LIST);
		EXPR:TYPE[E]←scalar_VALUE;
		EXPR:OP[E]←null;
		EXPR:ID[E]←"GARB_ID";
		EXPR_LIST:NEXT[EL]←EXPRS;
		EXPR_LIST:EXP[EL]←E;
		EXPRS←EL;
		GO TO RAISE;
		β;

procedure vmake_vvtrans_R(BOOLEAN vm_vv);
		α RPTR (EXPR_LIST) CUR_PARTS,TEMP; 
		RPTR (EXPR) CUR_EXPR,TEMP2;
		RPTR (DIMENS_EXPONENT) D_PTR;
		STRING E_OP;INTEGER E_TYPE; INTEGER TYPE_VALUE;
		INTEGER I;
		IF VM_VV THEN α E_OP←"VMAKE";E_TYPE←vector_VALUE; TYPE_VALUE← scalar_VALUE; β
			 ELSE α E_OP←"VVVTRANS"; E_TYPE←rot_VALUE; TYPE_VALUE←vector_VALUE; β;
		D_PTR←NULL_RECORD;
		FOR I←1 STEP 1 UNTIL 3 DO
			α
			IF EXPRS=NULL_RECORD THEN FAIL_UP(107,"Can't reduce expression.");
			TEMP←EXPRS;
			EXPRS←EXPR_LIST:NEXT[EXPRS];
			EXPR_LIST:NEXT[TEMP]←CUR_PARTS;
			CUR_PARTS←TEMP;
			IF TYPE_VALUE≠EXPR:TYPE[TEMP2←EXPR_LIST:EXP[CUR_PARTS]]
				THEN ERROR(108,"Type mismatch");
			IF D_PTR=NULL_RECORD THEN D_PTR←EXPR:DIMEN[TEMP2]
				ELSE D_PTR←CHECK_DIMENSIONS("VECTOR",D_PTR,EXPR:DIMEN[TEMP2]);
			β;
		CUR_EXPR←NEW_RECORD(EXPR);
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		EXPR:OP[CUR_EXPR]←E_OP;
		EXPR:TYPE[CUR_EXPR]←E_TYPE;
		EXPR:DIMEN[CUR_EXPR]←D_PTR;
		TEMP←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:EXP[TEMP]←CUR_EXPR;
		EXPR_LIST:NEXT[TEMP]←EXPRS;
		EXPRS←TEMP;
		β;

procedure vmake_R;
	vmake_vvtrans_R(TRUE);		! VMAKE found;

procedure vvtrans_R;
	vmake_vvtrans_R(FALSE);		! VVTRANS FOUND;
!	tmake_r, fmake_r;

procedure ft_make(Boolean tr);
		α RPTR (EXPR_LIST) CUR_PARTS,TEMP;
		RPTR (EXPR) E1,E2,E3;
		STRING MAKE, FT;
		IF TR THEN α MAKE←"TMAKE"; FT←" trans"; β
			ELSE α MAKE←"FMAKE"; FT←" frame"; β;
		IF EXPRS=NULL_RECORD OR EXPR_LIST:NEXT[EXPRS]=NULL_RECORD THEN
			FAIL_UP(108,"Can't reduce expression.");
		E1←EXPR_LIST:EXP[EXPRS];
		EXPRS←EXPR_LIST:NEXT[EXPRS];
		E2←EXPR_LIST:EXP[EXPRS];
		IF EXPR:TYPE[E1]≠vector_VALUE THEN
			α E3←E1; E1←E2; E2←E3; β;
		IF EXPR:TYPE[E1]≠vector_VALUE OR EXPR:TYPE[E2]≠rot_VALUE
			THEN ERROR(109,"Type mismatch.");
		CHECK_DIMENSIONS("vector part of"&FT,EXPR:DIMEN[E1],DISTANCE_DIMENS);
		CHECK_DIMENSIONS("rot part of"&FT,EXPR:DIMEN[E2],ANGLE_DIMENS);
		TEMP←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:EXP[TEMP]←E1;
		CUR_PARTS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
		EXPR_LIST:EXP[CUR_PARTS]←E2;
		E3←NEW_RECORD(EXPR);
		EXPR:PARTS[E3]←CUR_PARTS;
		EXPR:OP[E3]←MAKE;
		EXPR:TYPE[E3]←trans_VALUE;
IF ¬TR THEN	EXPR:DIMEN[E3]←distance_dimens; ! TO ENSURE THAT TRANS*TRANS WILL
				NOT GIVE DIMENSIONS OF DISTANCE*DISTANCE;
		EXPR_LIST:EXP[EXPRS]←E3;
		β;


procedure tmake_R;
	ft_make(TRUE);	! TMAKE FOUND;

procedure fmake_R;
	ft_make(FALSE);	! FMAKE FOUND;
!	sneg_R,rinv_R, sabs_R;

procedure sneg_R;
		α RPTR (EXPR_LIST) CUR_PARTS,TEMP; ! "SNEG" FOUND;
		RPTR (EXPR) CUR_EXPR,E1,E2,E3;
		IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
		E1←EXPR_LIST:EXP[EXPRS];
		IF EXPR:TYPE[E1]≠scalar_VALUE THEN ERROR(112,"You can only take the opposite of scalars."
			&crlf&"Continue will pass the bug through.");
		CUR_EXPR←NEW_RECORD(EXPR);
		EXPR:OP[CUR_EXPR]←"SNEG";
		CUR_PARTS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:EXP[CUR_PARTS]←E1;
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		EXPR:TYPE[CUR_EXPR]←scalar_VALUE;
		EXPR:DIMEN[CUR_EXPR]←EXPR:DIMEN[E1];
		EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
		β;

procedure rinv_R;
		α RPTR (EXPR_LIST) CUR_PARTS,TEMP;  ! "RINV" FOUND;
		RPTR (EXPR) CUR_EXPR,E1;
		IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
		E1←EXPR_LIST:EXP[EXPRS];
		CUR_EXPR←NEW_RECORD(EXPR);
		IF EXPR:TYPE[E1]=rot_VALUE THEN
			α
			EXPR:OP[CUR_EXPR]←"RINV";
			EXPR:TYPE[CUR_EXPR]←rot_VALUE;
			β
		ELSE IF EXPR:TYPE[E1]=trans_VALUE THEN
			α
			EXPR:OP[CUR_EXPR]←"TINVRT";
			EXPR:TYPE[CUR_EXPR]←trans_VALUE;
			β
		ELSE ERROR(112,"You can only take the inverse of rotations and transforms."
			&crlf&"Continue will pass bug through.");
		CUR_PARTS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:EXP[CUR_PARTS]←E1;
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		EXPR:DIMEN[CUR_EXPR]←INVERSE_DIMENSIONS(EXPR:DIMEN[E1]);
		EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
		β;

procedure sabs_R;
		α ! "SABS" SHOULD BE HANDLED IN P_EXP; ERROR(-1,"PARSER ERROR"); β;
!	plus_R,minus_R;

procedure plus_minus_R(boolean plus);
		α
		STRING S,V,TV, COMMM;
		RPTR (EXPR_LIST) CUR_PARTS,TEMP;
		RPTR (EXPR) CUR_EXPR,E1,E2,E3;
		IF PLUS THEN α S←"SADD"; V←"VADD"; TV←"TVADD"; COMMM←"addition "; β
			ELSE α S←"SSUB"; V←"VSUB"; TV←"TVSUB"; COMMM←"subtraction "; β;
		IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
		E1←EXPR_LIST:EXP[EXPRS];
		EXPRS←EXPR_LIST:NEXT[EXPRS];
		IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
		E2←EXPR_LIST:EXP[EXPRS];
		IF EXPR:TYPE[E1]≥EXPR:TYPE[E2] THEN α E3←E1; E1←E2; E2←E3; β;
		TEMP←NEW_RECORD(EXPR_LIST);
		CUR_PARTS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
		EXPR_LIST:EXP[TEMP]←E1;
		EXPR_LIST:EXP[CUR_PARTS]←E2;
		CUR_EXPR←NEW_RECORD(EXPR);
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		EXPR:DIMEN[CUR_EXPR]←CHECK_DIMENSIONS(COMMM&"expression",EXPR:DIMEN[E1],EXPR:DIMEN[E2]);
		IF EXPR:TYPE[E1]=scalar_VALUE THEN
			α
			IF EXPR:TYPE[E2]≠scalar_VALUE THEN ERROR(109,"Type mismatch.");
			EXPR:OP[CUR_EXPR]←S;
			EXPR:TYPE[CUR_EXPR]←scalar_VALUE;
			β
		ELSE IF EXPR:TYPE[E1]=vector_VALUE THEN
			α
			IF EXPR:TYPE[E2]=vector_VALUE THEN
				α
				EXPR:OP[CUR_EXPR]←V;
				EXPR:TYPE[CUR_EXPR]←vector_VALUE;
				β
			ELSE IF EXPR:TYPE[E2]=trans_VALUE THEN
				α
				EXPR:OP[CUR_EXPR]←TV;
				EXPR:TYPE[CUR_EXPR]←trans_VALUE;
				β
			β
		ELSE ERROR(109,"Type mismatch");
		EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
		β;

procedure plus_R;
	plus_minus_R(TRUE);	! "+" FOUND;

procedure minus_R;
	plus_minus_R(FALSE);	! "-" FOUND;

!	times_R;

procedure times_R;
		α RPTR (EXPR_LIST) CUR_PARTS,TEMP; ! "*" FOUND;
		RPTR (EXPR) CUR_EXPR,E1,E2,E3;
		IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
		E1←EXPR_LIST:EXP[EXPRS];
		EXPRS←EXPR_LIST:NEXT[EXPRS];
		IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
		E2←EXPR_LIST:EXP[EXPRS];
		IF EXPR:TYPE[E2]=vector_VALUE THEN α E3←E1; E1←E2; E2←E3; β;
		TEMP←NEW_RECORD(EXPR_LIST);
		CUR_PARTS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
		EXPR_LIST:EXP[TEMP]←E1;
		EXPR_LIST:EXP[CUR_PARTS]←E2;
		CUR_EXPR←NEW_RECORD(EXPR);
		EXPR:DIMEN[CUR_EXPR]←
			MULTIPLY_DIMENSIONS(EXPR:DIMEN[E1],EXPR:DIMEN[E2]);
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		IF EXPR:TYPE[E1]≤trans_VALUE
		    THEN CASE EXPR:TYPE[E1] OF
			α "E1"

[scalar_VALUE]		α
			IF EXPR:TYPE[E2]≠scalar_VALUE THEN ERROR(109,"Type mismatch.");
			EXPR:OP[CUR_EXPR]←"SMUL";
			EXPR:TYPE[CUR_EXPR]←scalar_VALUE;
			β;

[vector_VALUE]		IF EXPR:TYPE[E2]≤trans_VALUE
			    THEN CASE EXPR:TYPE[E2] OF
				α "E2"

		[scalar_VALUE]	α
				EXPR:OP[CUR_EXPR]←"SVMUL";
				EXPR:TYPE[CUR_EXPR]←vector_VALUE;
				β;

		[vector_VALUE]	ERROR(109,"Type mismatch.");

		[rot_VALUE]	α
				EXPR:OP[CUR_EXPR]←"RVMUL";
				EXPR:TYPE[CUR_EXPR]←vector_VALUE;
				EXPR:DIMEN[CUR_EXPR]←EXPR:DIMEN[E1];
				β;

		[frame_VALUE]	ERROR(109,"Type mismatch.");

		[plane_VALUE]	ERROR(109,"Type mismatch.");

		[trans_VALUE]	α
				EXPR:OP[CUR_EXPR]←"TVMUL";
				EXPR:TYPE[CUR_EXPR]←vector_VALUE;
				β

				β "E2"
			    ELSE ERROR(109,"Type mismatch.");

[rot_VALUE]		α
			IF EXPR:TYPE[E2]≠rot_VALUE THEN ERROR(109,"Type mismatch.");
			EXPR:OP[CUR_EXPR]←"RRMUL";
			EXPR:TYPE[CUR_EXPR]←rot_VALUE;
			EXPR:DIMEN[CUR_EXPR]←ANGLE_DIMENS;
			β;

[frame_VALUE]		ERROR(120,"Type mismatch.");

[plane_VALUE]		ERROR(120,"Type mismatch.");

[trans_VALUE]		α
			IF EXPR:TYPE[E2]≠trans_VALUE THEN ERROR(109,"Type mismatch.");
			EXPR:OP[CUR_EXPR]←"TTMUL";
			EXPR:TYPE[CUR_EXPR]←trans_VALUE;
			β

			β "E1"

		    ELSE ERROR(109,"Type mismatch");
		EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
		β;
!	rot_R, wrt_R;

procedure rot_R;
		α RPTR (EXPR_LIST) CUR_PARTS,TEMP; ! "ROT" FOUND;
		RPTR (EXPR) CUR_EXPR,E1,E2,E3;
		IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
		E1←EXPR_LIST:EXP[EXPRS];
!		CHECK_DIMENSIONS("angle part of ROT", EXPR:DIMEN[E1],ANGLE_DIMENS);
		IF EXPR:TYPE[E1]≠scalar_VALUE THEN ERROR(109,"Type mismatch.");
		EXPRS←EXPR_LIST:NEXT[EXPRS];
		IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
		E2←EXPR_LIST:EXP[EXPRS];
		IF EXPR:TYPE[E2]≠vector_VALUE THEN ERROR(109,"Type mismatch.");
		TEMP←NEW_RECORD(EXPR_LIST);
		CUR_PARTS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
		EXPR_LIST:EXP[TEMP]←E1;
		EXPR_LIST:EXP[CUR_PARTS]←E2;
		CUR_EXPR←NEW_RECORD(EXPR);
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		EXPR:OP[CUR_EXPR]←"AXW_ROTN";
		EXPR:TYPE[CUR_EXPR]←rot_VALUE;
		EXPR:DIMEN[CUR_EXPR]←ANGLE_DIMENS;
		EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
		β;

procedure wrt_R;
		α RPTR (OP_LIST) OP_SAVE;
		COMMENT
			vector WRT frame 
			GETS TRANSLATED TO
			(TVMUL (ORIENT frame) vector)
			SO THIS PROCEDURE MERELY CHAANGES THE TOP OF THE OP_LIST
			DOING NO REAL REDUCTION.  THE REDUCTION IS THEN DONE ON THE
			FOLLOWING TWO PASSES.  (NOTE: THIS MEANS THAT THE PRECEDENCE
			OF WRT IS DIFFERENT DEPENDING ON WHICH SIDE YOU SEE IT FROM.

		NOTE THAT ABOVE IS NOT CORRECT, BUT HERE IS WHAT'S DONE.
[vector WRT frame] gets translated
into (RVMUL (ORIENT frame) vector) instead of (TVMUL (ORIENT frame) vector).
That's because (ORIENT frame) returns a rotation, not a translation.
		;
		OP_LIST:OP[OPS]←times_X;
		OPSAVE←OPS;
		OPS←NEW_RECORD(OP_LIST);
		OP_LIST:NEXT[OPS]←OPSAVE;
		OP_LIST:PRIORITY[OPS]← SPECIAL_INFO;
		OP_LIST:NUM_OF_ARGS[OPS]←OP_NUM[orient_X];
		OP_LIST:FUNC[OPS]←FALSE;
		OP_LIST:ARG_DEP[OPS]←OP_BOOL[orient_X];
		OP_LIST:OP[OPS]←orient_X;
		COMMENT NOTE THAT THE END OF REDUCE (where the execution goes next)
			WILL THROW AWAY THE TOP OP ON OP_LIST, SO WE'RE GOING TO
			PUT ON A DUMMY OPERATOR;
		OPSAVE←OPS;
		OPS←NEW_RECORD(OP_LIST);
		OP_LIST:NEXT[OPS]←OPSAVE;
		β;
!	→_R;

procedure →_R;
		α RPTR (EXPR_LIST) CUR_PARTS,TEMP; ! "→" FOUND;
		RPTR (EXPR) CUR_EXPR,E1,E2,E3;
		IF EXPRS=NULL_RECORD THEN FAIL_UP(109,"Can't reduce expression.");
		E1←EXPR_LIST:EXP[EXPRS];
		EXPRS←EXPR_LIST:NEXT[EXPRS];
		IF EXPRS=NULL_RECORD THEN FAIL_UP(110,"Can't reduce expression.");
		E2←EXPR_LIST:EXP[EXPRS];
		IF EXPR:TYPE[E1]≠EXPR:TYPE[E2] THEN ERROR(111,"Type mismatch.");
		TEMP←NEW_RECORD(EXPR_LIST);
		CUR_PARTS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[CUR_PARTS]←TEMP;
		EXPR_LIST:EXP[TEMP]←E1;
		EXPR_LIST:EXP[CUR_PARTS]←E2;
		CUR_EXPR←NEW_RECORD(EXPR);
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		EXPR:DIMEN[CUR_EXPR]←
			MULTIPLY_DIMENSIONS(EXPR:DIMEN[E1],EXPR:DIMEN[E2]);
		IF EXPR:TYPE[E1]=vector_VALUE THEN
			α
			EXPR:OP[CUR_EXPR]←"VTOV";
			EXPR:TYPE[CUR_EXPR]←rot_VALUE;
			β
		ELSE IF EXPR:TYPE[E1]=trans_VALUE THEN
			α
			EXPR:OP[CUR_EXPR]←"FTOF";
			EXPR:TYPE[CUR_EXPR]←trans_VALUE;
			β
		ELSE ERROR(109,"Type mismatch");
		EXPR_LIST:EXP[EXPRS]←CUR_EXPR;
		β;
!	reduce execution starts here;

	CUR_OP_NUM←OP_LIST:OP[OPS];
	IF ¬(1 ≤ CUR_OP_NUM ≤ op_count)
		THEN FAIL_UP(1030,"Trying to parse expression and found garbage.");
	IF OP_BOOL[CUR_OP_NUM] THEN
		CASE		CUR_OP_NUM  -  first_true_op		OF
		α

redefine xx(str1, i1, boole, i2, i3, i4, str2)=[
    ifc boole
	thenc
	redefine xx_temp=ifc "str2"=null thenc [str1] elsec [str2] endc & "_R";
	xx_temp;
	endc ];
operator_definitions;

		β
	ELSE	α RPTR(EXPR_LIST) CUR_PARTS,TEMP;
		RPTR (EXPR) CUR_EXPR;
		INTEGER I;
		FOR I←1 STEP 1 UNTIL OP_NUM[CUR_OP_NUM] DO
			α
			IF EXPRS=NULL_RECORD THEN FAIL_UP(107,"Can't reduce expression.");
			TEMP←EXPRS;
			EXPRS←EXPR_LIST:NEXT[EXPRS];
			EXPR_LIST:NEXT[TEMP]←CUR_PARTS;
			CUR_PARTS←TEMP;
			IF TYPE_OF_ARGS[CUR_OP_NUM]≠EXPR:TYPE[EXPR_LIST:EXP[CUR_PARTS]]
				AND TYPE_OF_ARGS[CUR_OP_NUM]≥0
				THEN ERROR(108,"Type mismatch");
			β;
		CUR_EXPR←NEW_RECORD(EXPR);
		CASE DIMEN_CHANGES[CUR_OP_NUM] OF
			α

[ignore_dimen]		;

[same_dimen]		α
			EXPR:DIMEN[CUR_EXPR]←EXPR:DIMEN[EXPR_LIST:EXP[CUR_PARTS]];
			β;

[inverse_dimen]		α
			EXPR:DIMEN[CUR_EXPR]←
				INVERSE_DIMENSIONS(EXPR:DIMEN[EXPR_LIST:EXP[CUR_PARTS]]);
			β;

[check_dimen]		α RPTR(EXPR) E1,E2;
			E1←EXPR_LIST:EXP[CUR_PARTS];
			E2←EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]];
			EXPR:DIMEN[CUR_EXPR]←CHECK_DIMENSIONS("expression",EXPR:DIMEN[E1],EXPR:DIMEN[E2]);
			β;

[multiply_dimen]	EXPR:DIMEN[CUR_EXPR]←
				MULTIPLY_DIMENSIONS(
				EXPR:DIMEN[EXPR_LIST:EXP[CUR_PARTS]],
				EXPR:DIMEN[EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]]]);

[divide_dimen]		EXPR:DIMEN[CUR_EXPR]←
				DIVIDE_DIMENSIONS(
				EXPR:DIMEN[EXPR_LIST:EXP[CUR_PARTS]],
				EXPR:DIMEN[EXPR_LIST:EXP[EXPR_LIST:NEXT[CUR_PARTS]]])
			
			β;
		EXPR:PARTS[CUR_EXPR]←CUR_PARTS;
		EXPR:OP[CUR_EXPR]←OP_ARRAY[CUR_OP_NUM];
		IF RESULT_TYPE[CUR_OP_NUM]≥0 THEN
			EXPR:TYPE[CUR_EXPR]←RESULT_TYPE[CUR_OP_NUM] ELSE
			EXPR:TYPE[CUR_EXPR]←EXPR:TYPE[EXPR_LIST:EXP[CUR_PARTS]];
		TEMP←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[TEMP]←EXPRS;
		EXPR_LIST:EXP[TEMP]←CUR_EXPR;
		EXPRS←TEMP;
		β;


RAISE:	OPS←OP_LIST:NEXT[OPS];
	β;
! printexpr;

RECURSIVE PROCEDURE PRINTEXPR(RPTR (EXPR) E);
IF EQU(EXPR:OP[E],null) THEN OUTEXPR←OUTEXPR&EXPR:ID[E]
ELSE	α RPTR (EXPR_LIST) SUBS;
	OUTEXPR←OUTEXPR&"("&EXPR:OP[E];
	SUBS←EXPR:PARTS[E];
	WHILE SUBS≠NULL DO
		α
		OUTEXPR←OUTEXPR&" ";
		PRINTEXPR(EXPR_LIST:EXP[SUBS]);
		SUBS←EXPR_LIST:NEXT[SUBS];
		β;
	OUTEXPR←OUTEXPR&")";
	β;
! string_expr;

STRING PROCEDURE STRING_EXPR;
α
STRING BODY,NEXT_STRING; BOOLEAN TO_FOR; INTEGER K1,K2;
GET_TOKEN; BODY←NULL;
IF TYPE_OF_TOKEN=STRING_TOKEN 
  THEN NEXT_STRING←TOKEN
  else if type_of_token=numeric_token 
    then next_string←NULL&realnum
    ELSE ERROR(37, "Need string token here");
GET_TOKEN;
WHILE TOKEN="&" OR TOKEN="[" DO
  α 
  IF TOKEN="&"
    THEN
    α GET_TOKEN; IF BODY≠NULL THEN BODY←BODY&NEXT_STRING ELSE BODY←NEXT_STRING;
    IF TYPE_OF_TOKEN=STRING_TOKEN 
      THEN NEXT_STRING←TOKEN
      else if type_of_token=numeric_token 
	then next_string←NULL& realnum
	ELSE ERROR(37, "Need string token here");
    GET_TOKEN;
    β
    ELSE  
    α BOOLEAN TOFOR; GET_TOKEN;IF TYPE_OF_TOKEN≠NUMERIC_TOKEN THEN ERROR(38,"Need numeric token here") else k1←realnum;
    get_token;
    IF EQU(TOKEN,"TO") OR EQU(TOKEN,"FOR")
      THEN 
      α IF TOKEN="TO" THEN TOFOR←TRUE ELSE TOFOR←FALSE;	GET_TOKEN; K2←REALNUM;
      GET_TOKEN; IF TOKEN≠"]" THEN ERROR_REJECT(39, "Need ""]"" here, continue will insert.");
      β
      ELSE ERROR(37, "Need TO or FOR here");
    IF TOFOR THEN NEXT_STRING←NEXT_STRING[K1 TO K2] ELSE NEXT_STRING←NEXT_STRING[K1 FOR K2];
    GET_TOKEN;
    β;
  β;
REJECT←TRUE;
RETURN(BODY&NEXT_STRING);
β;
! p_exp2;

! PARSE EXPRESSIONS AND SAVE PARSED STRUCTURE INTERNALLY FOR LATER PRINTING;

PROCEDURE P_EXP2;
α RPTR (ID_LIST) POINT; LABEL FLUSH;

	PROCEDURE F_EXP(INTEGER IP; STRING SP);
	α RPTR(EXPR)E;
	ERROR(IP,SP&crlf&"Continue will attempt to flush expression.");
	WHILE (	TYPE_OF_TOKEN=id_token
		OR (EQU(TOKEN,"(") AND ¬OP_EXPECTED)
		OR TYPE_OF_TOKEN=numeric_token
		OR (operator_beg ≤ TYPE_OF_RES_WORD ≤ operator_end)
		OR TYPE_OF_RES_WORD=declare_RES)
	    DO GET_TOKEN;
	OPS←NULL_RECORD;
	if exprs≠null_record then
	    α
	    E←NEW_RECORD(EXPR);
	    EXPR:TYPE[E]←scalar_VALUE;
	    EXPR:ID[E]←"GARB_ID";
	    EXPR_LIST:NEXT[EXPRS]←NULL_RECORD;
	    EXPR_LIST:EXP[EXPRS]←E;
	    β;
	GO TO FLUSH;
	β;

BOOLEAN PROCEDURE MODIFY_CONTINUE(INTEGER ERR_NO; STRING MESS);
	α CAN_MODIFY←TRUE; ERROR(ERR_NO,"Modifiable error, continue will try to recover"&crlf&MESS);
	IF MODIFIED
	  THEN α CURLINE←CURLINER←ERROR_BUFFER; REJECT←FALSE; GET_TOKEN; MODIFIED←FALSE; RETURN(TRUE); β
	  ELSE α CAN_MODIFY←FALSE; RETURN(MODIFIED) β;
	β;

!	parse_special;

procedure parse_special;
    α "parse_special" integer j;

define expected_ops=[
xx([(],		-1,		-1,		false,	false)
xx([|],		sabs_X,		-1,		true,	false)
! xx([-],		sneg_X,		vector_RES,	false,	false) ;
xx([/],		rinv_X,		vector_RES,	false,	false)
xx(NOT,		not_X,		not_RES,	false,	false)
xx([¬],		not_X,		not_RES,	false,	false)
xx(VVTRANS,	vvtrans_X,	vector_RES,	false,	true)
xx(ROT,		rot_X,		vector_RES,	true,	true)
xx(VVROT,	vvrot_X,	vector_RES,	false,	true)
xx(VDOT,	vdot_X,		vector_RES,	false,	true)
xx(ANGLE,	angle_X,	vector_RES,	false,	true)
xx(INV,		rinv_X,		vector_RES,	false,	true)
];

		define
op_case=0;
		redefine xx(token, op_num, prior, arg_dep, func)=[
		    redefine op_case=op_case+1;];
		expected_ops;

		redefine xx(token, op_num, prior, arg_dep, func)=["token",];
		preload_array(
expected_name,	expected_ops, [own string], 0, op_case);
		redefine xx(token, op_num, prior, arg_dep, func)=[op_num,];
		preload_array(
expected_X,	expected_ops, [own integer], 0, op_case);
		redefine xx(token, op_num, prior, arg_dep, func)=[prior,];
		preload_array(
expected_prior,	expected_ops, [own integer], 0, op_case);
		redefine xx(token, op_num, prior, arg_dep, func)=[arg_dep,];
		preload_array(
expected_arg,	expected_ops, [own boolean], 0, op_case);
		redefine xx(token, op_num, prior, arg_dep, func)=[func,];
		preload_array(
expected_func,	expected_ops, [own boolean], 0, op_case);
	
OPSAVE←OPS;  OPS←NEW_RECORD(OP_LIST);

OP_LIST:NEXT[OPS]←OPSAVE;
 IF TOKEN="+" OR TOKEN = "-" THEN SPECIAL_INFO←TIMES_X;
OP_LIST:PRIORITY[OPS] ← SPECIAL_INFO;
for j←0 step 1 until op_case-1 do if equ(token,expected_name[j]) then done;
if j ≤ op_case-1
    then
	α integer k;
	OP_LIST:PRIORITY[OPS] ← expected_prior[j];
	OP_LIST:OP[OPS] ← k ← expected_X[j];
	OP_LIST:NUM_OF_ARGS[OPS] ← if k<0 then 1 else op_num[k];
	op_list:count[ops] ← 0;
	OP_LIST:ARG_DEP[OPS] ← expected_arg[j];
	op_list:func[ops] ← expected_func[j];
	if token="(" then no_op_so_far←true;
	β
    ELSE IF EQU(TOKEN,"⊗")
	THEN
	    α
	    EXP1←NEW_RECORD(EXPR);
	    EXPR:TYPE[EXP1]←trans_VALUE;
	    EXPR:OP[EXP1]←null;
	    IF EQU(CURRENT_FRAME,null) THEN
	    	ERROR(1111,"⊗ used outside of MOVE, AFFIX, or UNAFFIX statement is illegal.");
	    EXPR:ID[EXP1]←CURRENT_FRAME;
	    EXPR:DIMEN[EXP1]←distance_dimens;
	    EXPRSAVE←EXPRS;
	    EXPRS←NEW_RECORD(EXPR_LIST);
	    EXPR_LIST:NEXT[EXPRS]←EXPRSAVE;
	    EXPR_LIST:EXP[EXPRS]←EXP1;
	    OPS←OP_LIST:NEXT[OPS];
	    OP_EXPECTED←TRUE;
	    β
	ELSE IF TYPE_OF_RES_WORD=declare_RES
	    THEN
		α "declare_RES"
		case special_info of
		    α "special_info"

[vector_VALUE]			α ! VMAKE FOUND;
				OP_LIST:OP[OPS] ← vmake_X;
				OP_LIST:NUM_OF_ARGS[OPS] ← op_num[vmake_X];
				β;

[frame_VALUE]			α ! FMAKE FOUND;
				OP_LIST:OP[OPS] ← fmake_X;
				OP_LIST:NUM_OF_ARGS[OPS] ← op_num[fmake_X];
				β;

[trans_VALUE]			α ! TMAKE FOUND;
				OP_LIST:OP[OPS] ← tmake_X;
				OP_LIST:NUM_OF_ARGS[OPS] ← op_num[tmake_X];
				β;

[0]
[scalar_VALUE]
[rot_VALUE]
[plane_VALUE]			F_EXP(103,"Illegal operator.")

		    β "special_info";
		OP_LIST:COUNT[OPS]←0;
		OP_LIST:ARG_DEP[OPS]←FALSE;
		OP_LIST:FUNC[OPS]←TRUE;
		β "declare_RES"
	
	    ELSE if special_info
		then
		    α
		    IF TOKEN="+" OR TOKEN="-" 
			then
			IF NO_OP_SO_FAR THEN
			α
			EXP1←NEW_RECORD(EXPR);
			EXPR:TYPE[EXP1]←scalar_VALUE;
			EXPR:OP[EXP1]←null;
			EXPR:ID[EXP1]←token&"1.000000";
			EXPRSAVE←EXPRS;
			EXPRS←NEW_RECORD(EXPR_LIST);
			EXPR_LIST:NEXT[EXPRS]←EXPRSAVE;
			EXPR_LIST:EXP[EXPRS]←EXP1;
			β
			ELSE ERROR(25,"Cannot have two + or - together");
		    OP_LIST:OP[OPS]←SPECIAL_INFO;
		    OP_LIST:ARG_DEP[OPS]←OP_BOOL[SPECIAL_INFO];
		    OP_LIST:NUM_OF_ARGS[OPS]←OP_NUM[SPECIAL_INFO];
		    β
		else f_exp(200, "Doesn't make sense.");
	if equ(token,"(") then no_op_so_far←true else no_op_so_far←false;
    β "parse_special";
!	p_exp2 execution begins here, p_exp;
label re_try;
error_buffer←curliner;
GET_TOKEN;
re_try:
no_op_so_far←true;
OP_EXPECTED←FALSE;  EXPRS←NULL_RECORD; ops←NULL_RECORD; EXP1←EXP2←EXP3←NULL_RECORD;  OUTEXPR←null;


WHILE (	(TYPE_OF_TOKEN=id_token AND ID_TYPE<CM_LABEL_VALUE)
	OR (EQU(TOKEN,"(") AND ¬OP_EXPECTED)
	OR TYPE_OF_TOKEN=numeric_token
	OR (operator_beg ≤ TYPE_OF_RES_WORD ≤ operator_end)
	OR TYPE_OF_RES_WORD=declare_RES)
    DO
	α "while"
	IF OP_EXPECTED THEN
		α "op_expected"
		IF EQU(TOKEN,"ROT") THEN
			α
			TYPE_OF_TOKEN←reserved_token;
			TYPE_OF_RES_WORD←trans_RES;
			no_op_so_far←true;
			SPECIAL_INFO←rot_X;
			β;
		IF TYPE_OF_TOKEN≠reserved_token OR EQU(TOKEN,"(")
			THEN F_EXP(101,"Operation needed here.");
		α "termin_check" integer match, j; string str;
		match ← -1; j←0;
		for str ← ")", ",", "|" do
		    if equ(str, token)
			then α match ← j; done β
			else j ← j+1;
		if match ≥ 0
		    then case match of

			α "match"

	! ")";		α
			WHILE OPS≠NULL_RECORD AND OP_LIST:OP[OPS]≠-1 DO REDUCE;
			IF OPS=NULL_RECORD THEN done "while";
			OPS←OP_LIST:NEXT[OPS];
			IF OPS≠NULL_RECORD AND OP_LIST:FUNC[OPS]=TRUE THEN REDUCE;
			β;

	! ",";		α
			WHILE OPS≠NULL_RECORD AND OP_LIST:OP[OPS]≠-1 DO REDUCE;
			NO_OP_SO_FAR←TRUE;
			IF OPS=NULL THEN done "while";
			OP_EXPECTED←FALSE;
			β;

	! "|";		α
			WHILE OPS≠NULL_RECORD AND OP_LIST:OP[OPS]≠17 DO REDUCE;
			IF OPS=NULL_RECORD
				THEN F_EXP(105,"Mismatched vertical paren.");
			OPS←OP_LIST:NEXT[OPS];
			EXP1←NEW_RECORD(EXPR);
			EXPR:PARTS[EXP1]←NEW_RECORD(EXPR_LIST);
			EXPR_LIST:EXP[EXPR:PARTS[EXP1]]←EXPR_LIST:EXP[EXPRS];
			EXPR:DIMEN[EXP1]
				← EXPR:DIMEN[EXPR_LIST:EXP[EXPRS]];
			EXPR:TYPE[EXP1]←scalar_VALUE;
			CASE (EXPR:TYPE[EXPR_LIST:EXP[EXPRS]]) OF
				α
				[scalar_VALUE]	EXPR:OP[EXP1]←"SABS";
				[vector_VALUE]	EXPR:OP[EXP1]←"VMAGN";
				[rot_VALUE]	EXPR:OP[EXP1]←"RMAGN";
				ELSE		ERROR(106,"Type mismatch for |.|.")
				β;
			EXPR_LIST:EXP[EXPRS]←EXP1;
			β

			β "match"
		    ELSE
			α
			IF TYPE_OF_RES_WORD=0
				THEN F_EXP(1000,"Sorry, OP not implemented yet.");
			WHILE OPS≠NULL_RECORD AND OP_LIST:PRIORITY[OPS]≥TYPE_OF_RES_WORD
				DO REDUCE;
			OPSAVE←OPS;
			OPS←NEW_RECORD(OP_LIST);
			OP_LIST:NEXT[OPS]←OPSAVE;
			OP_LIST:PRIORITY[OPS]←TYPE_OF_RES_WORD;
			OP_LIST:NUM_OF_ARGS[OPS]←OP_NUM[SPECIAL_INFO];
			OP_LIST:FUNC[OPS]←FALSE;
			OP_LIST:ARG_DEP[OPS]←OP_BOOL[SPECIAL_INFO];
			OP_LIST:OP[OPS]←SPECIAL_INFO;
			OP_EXPECTED←FALSE;
			β
		β "termin_check"
		β "op_expected"

 	ELSE case TYPE_OF_TOKEN of

	    α "type_of_token"

[id_token]	α
		EXP1←NEW_RECORD(EXPR);
		EXPR:TYPE[EXP1]←ID_LIST:TYPE[TOKEN_PTR];
		EXPR:DIMEN[EXP1]←ID_LIST:DIMEN[TOKEN_PTR];
		EXPR:OP[EXP1]←null;
		EXPR:ID[EXP1]←TOKEN;
		EXPRSAVE←EXPRS;
		EXPRS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[EXPRS]←EXPRSAVE;
		EXPR_LIST:EXP[EXPRS]←EXP1;
		no_op_so_far←false;		
		OP_EXPECTED←TRUE;
		β;

[numeric_token]	α
		EXP1←NEW_RECORD(EXPR);
		EXPR:TYPE[EXP1]←scalar_VALUE;
		EXPR:OP[EXP1]←null;
		EXPR:ID[EXP1]←TOKEN;
		EXPRSAVE←EXPRS;
		EXPRS←NEW_RECORD(EXPR_LIST);
		EXPR_LIST:NEXT[EXPRS]←EXPRSAVE;
		EXPR_LIST:EXP[EXPRS]←EXP1;
		no_op_so_far←false;
		OP_EXPECTED←TRUE;
		β;

[undeclared_token]	if modify_continue(17, "Undeclared token  ⊂"&token&"⊃") then goto re_try;

[reserved_token]	parse_special;

[string_token]	F_EXP(100,"Illegal expression.")

		β "type_of_token";
	GET_TOKEN;
	β "while";
FLUSH:
REJECT←TRUE;
WHILE OPS≠NULL_RECORD DO REDUCE;
IF EXPRS=NULL
    THEN
	α
	if modify_continue(107,"Empty expression, continue will insert GARBID") then goto re_try;
	EXPRS←NEW_RECORD(EXPR_LIST);
	EXPR_LIST:EXP[EXPRS]←NEW_RECORD(EXPR);
	EXPR:ID[EXPR_LIST:EXP[EXPRS]]←"GARB_ID";
	β
    ELSE IF EXPR_LIST:NEXT[EXPRS]≠NULL THEN ERROR(107,"Can't reduce expression.");
EXP_DIMENS←EXPR:DIMEN[EXPR_LIST:EXP[EXPRS]];
PRINTEXPR(EXPR_LIST:EXP[EXPRS]);
EXP_TYPE←EXPR:TYPE[EXPR_LIST:EXP[EXPRS]];
β;

! PARSE EXPRESSIONS AND IMMEDIATELY PRINT EXPRESSION IN ALCODE FORM;

PROCEDURE P_EXP;
α
P_EXP2;
PRINT(OUTEXPR);
β;
! P_condition;

! CONDITION FINDER - NOT YET INCLUDED;

BOOLEAN PROCEDURE P_CONDITION(INTEGER PP;STRING PRELUDE);
α STRING COND,OP; LABEL FLUSH; RPTR(DIMENS_EXPONENT)PTR;

	PROCEDURE F_STATE(VALUE INTEGER IP; VALUE STRING SP);
	α STRING CLOSE; INTEGER I;
	ERROR(IP,SP&crlf&"Continue will flush statement.");
	WHILE ¬EQU(TOKEN,";") DO GET_TOKEN;
	REJECT←TRUE;
	NUM_OF_ERRORS_FLUSHED←NUM_OF_ERRORS_FLUSHED+1;
	GO TO FLUSH;
	β;

	
GET_TOKEN;

IF ID_TYPE=event_Value THEN
	α PRINT(PRELUDE& " " & TOKEN);
	RETURN(FALSE);
	β;


IF TYPE_OF_RES_WORD=cm_RES or equ(token,"FORCE") OR EQU(TOKEN,"TORQUE") THEN
    α "CM_RES"
    INTEGER FORCE_TYPE;
    IF SPECIAL_INFO=nil_CM
	THEN COND←TOKEN
	ELSE
	α ! YOU MIGHT WANT TO INCORPORATE ALL OF THIS INTO P_EXP2;
	FORCE_TYPE←SPECIAL_INFO;
	if force_type=torque_CM or force_type=force_cm
	    then
	    α COND←" FORCE "; GET_TOKEN;
	    IF FORCE_TYPE=TORQUE_CM THEN PTR←TORQUE_DIMENS ELSE PTR←FORCE_DIMENS;
	    IF EQU(TOKEN,"(")
		THEN
		α "("
		P_EXP2;
		IF EXP_TYPE≠vector_VALUE THEN F_STATE(1202,"Need vector here.");
		COND←COND&" "&OUTEXPR; GET_TOKEN;
		IF ¬EQU(TOKEN,")")
		    THEN ERROR(1201,"Need right paren here.  Continue will insert it.");
		GET_TOKEN;
		IF ¬TOKEN_EQU("=","<","≤",">","≥")
		    THEN ERROR(1202,"Need relational operator here");
		if TOKEN_EQU("≤")
		    THEN TOKEN←"<"
		    ELSE IF TOKEN_EQU(">") THEN TOKEN←"≥";
		PRINT(PRELUDE&" ("&COND& "  "&token); SPACING←SPACING+1; P_EXP;
		IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,PTR,"Force or Torque condition monitor")
		    THEN ERROR(49,"Need scalar quantity here.");
		if force_type=force_cm
		    then PRINT("  + )")
		    else if force_type=torque_cm then print(" - )") ELSE PRINT (" )");
		SPACING←SPACING-1; RETURN(FALSE);
		β "("
		ELSE
		IF TOKEN_EQU("=","<","≤","≥",">")
		    THEN
		    α "="
		    STRING REL_OP, SCAL_EXP,VECT_EXP,FFFF,PLUS_MIN;
		    REL_OP←TOKEN;
		    IF TOKEN_EQU("≤")
			THEN REL_OP←"<"
			ELSE IF TOKEN_EQU(">") THEN REL_OP←"≥";
		    IF FORCE_TYPE=FORCE_CM THEN PLUS_MIN ← " + " ELSE PLUS_MIN←" - ";
		    P_EXP2;  FFFF←null;
		    IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,PTR,"Force or Torque condition monitor")
			THEN ERROR(49,"Need scalar quantity here.");
		    SCAL_EXP←OUTEXPR; GET_TOKEN;
		    IF ¬TOKEN_EQU("ALONG","ABOUT")
			THEN
			α if ¬token_equ("WITH","ON",";")
				THEN ERROR(1205,"Need ALONG or ABOUT here, continue will insert it."); 
			REJECT←TRUE;
			β
			ELSE 
			α P_EXP2;
			IF ¬CHECK_EXP_TYPE_DIMENS(Vector_value, Nil_dimens,"direction vector")
			    then error(48, "Need vector expression here");
			vect_exp←outexpr; GET_TOKEN;
			IF ¬TOKEN_EQU("OF") THEN REJECT←TRUE
			    ELSE
			    α P_EXP2;
			    IF EXP_TYPE≠TRANS_VALUE AND EXP_TYPE≠ROT_VALUE 
				THEN ERROR(1206, "Need frame or rot value here");
			    FFFF←"( FORCE_FRAME "&outexpr; GET_TOKEN;
			    IF ¬TOKEN_EQU("IN")
				THEN α REJECT←TRUE; FFFF←FFFF& " # )"; β
				ELSE
				α GET_TOKEN;
				IF TOKEN_EQU("WORLD","STATION","FIXED")
				    THEN FFFF←FFFF & " # )"
				    ELSE
				    IF TOKEN_EQU("HAND","BHAND","YHAND","MOVING")
					THEN FFFF←FFFF& " ⊗ )"
					ELSE 
					α ERROR(1209, "Need FIXED or MOVING here, Continue will treat as station");
					FFFF←FFFF&" # )";
					β;
				GET_TOKEN;
				if ¬token_equ("COORD","COORDS","COORDINATES")
				    THEN REJECT←TRUE;
				β;
			    β;
			β;
		    print(PRELUDE);
		    PRINT("("&COND& "  "&VECT_EXP&"  "
						& REL_OP & "  " & SCAL_EXP& "  "&
						 PLUS_MIN & FFFF& "  )");
		    β "="
		    ELSE ERROR(1204, "Need relational operator here");
		β
		ELSE
		IF FORCE_TYPE=duration_CM
		    THEN
		    α PTR←TIME_DIMENS; cond← " DURATION "; GET_TOKEN;
		    PRINT(PRELUDE&" ("&COND& "  "&token);
		    SPACING←SPACING+1; P_EXP;
		    IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,PTR,"Duration condition monitor")
			 THEN ERROR(49,"Need scalar quantity here.");
		    PRINT (" )"); SPACING←SPACING-1; RETURN(FALSE);
		    β
		    ELSE
		    α ERROR(1203, "Only force or torque condition monitor allowed");
		    print(" )");
		    β;
	β;

    β "CM_RES"

    ELSE
    α P_EXP2;
    IF EXP_TYPE≠boole_Value and EXP_TYPE≠scalar_VALUE
	THEN F_STATE(44, "Need boolean expression or force_type predicate in condition monitor");
    PRINT(PRELUDE); print(outexpr); return(false);
    β;

FLUSH:	RETURN(TRUE);
β;
! P_clauses, T_gen;

PROCEDURE P_CLAUSES;
α "P_CLAUSES"
BOOLEAN T; LABEL FLUSH; BOOLEAN ICMT;STRING LABL; INTEGER LAB_TYPE;

	PROCEDURE F_STATE(VALUE INTEGER IP; VALUE STRING SP);
	α STRING CLOSE; INTEGER I;
	ERROR(IP,SP&crlf&"Continue will flush statement.");
	WHILE ¬EQU(TOKEN,";") DO GET_TOKEN;
	REJECT←TRUE;
	NUM_OF_ERRORS_FLUSHED←NUM_OF_ERRORS_FLUSHED +1;
	GO TO FLUSH;
	β;

ICMT←INSIDE_CONDITION_MONITOR; 
T←TRUE; GET_TOKEN;
WHILE T DO
	α
	LABL←NULL;
	IF (LAB_TYPE←ID_TYPE)=CM_LABEL_VALUE
	  THEN  IF DEFINED(TOKEN_PTR)
	    THEN ERROR(123,TOKEN& " already used.")
	    ELSE
	    α DEFIN(TOKEN_PTR); LABL←TOKEN;
	      INSIDE_CONDITION_MONITOR←TRUE;
	      GET_TOKEN;
	      IF ¬EQU(TOKEN,":") THEN ERROR(23,"Need colon after label " & LABL & " .") ELSE GET_TOKEN;
	    β;


	IF (TYPE_OF_RES_WORD=on_RES) AND ( (LABL=NULL) OR (LAB_TYPE=CM_LABEL_VALUE) )
	  THEN
	  α
	  INSIDE_CONDITION_MONITOR←TRUE;
	  IF EQU(TOKEN,"ON") THEN P_CONDITION(2,"( "&LABL& "ON +")
		ELSE α CHECK_NEXT_TOKEN(37, NULL,"ON"); P_CONDITION(2,"( " & LABL& "ON -"); β;
	  SPACING←SPACING+1;GET_TOKEN;
	  IF ¬EQU(TOKEN,"DO") THEN ERROR_REJECT(45,"Need DO here.  Continue will insert it.");
		P_STATEMENT;SPACING←SPACING-1; PRINT(")"); GET_TOKEN;
		β
	ELSE IF EQU(TOKEN,"(") THEN
		α INTEGER C; STRING TEMP;
		! LEFT PAREN FOUND - STAIGHT TRANSFER;
		C←1; TEMP←"(";
		WHILE C>0 DO
			α
			TEMP←TEMP&READ(paren_cr_break);
			IF BRCHAR="(" 
			  THEN C←C+1
			  ELSE IF BRCHAR=")" 
			    THEN C←C-1
			    ELSE α PRINT(TEMP);	TEMP←NULL; β;
			β;
		PRINT(TEMP); GET_TOKEN;
		β
	ELSE IF ¬(move_beg ≤ TYPE_OF_RES_WORD ≤ move_end) THEN
		α
		! END OF MOVE STATEMENT FOUND;
		REJECT←TRUE; T←FALSE;
		β
	ELSE CASE TYPE_OF_RES_WORD - move_beg OF
		α


[via_X]		α ! VIA CLAUSE FOUND;
		PRINT("(VIA ");	SPACING←SPACING+1; P_EXP;
		IF EXP_TYPE≠frame_exp_VALUE THEN ERROR(1202, "Need trans value expression here");
		GET_TOKEN;
		IF EQU(TOKEN,",") THEN
			α  SPACING←SPACING-1; PRINT(")");
	 		WHILE EQU(TOKEN,",") DO
	 			α
				PRINT("(VIA "); SPACING←SPACING+1; P_EXP;
				IF EXP_TYPE≠frame_exp_VALUE THEN ERROR(1202, "Need trans value expression here");
				SPACING←SPACING-1; PRINT(")"); GET_TOKEN;
	 			β;
			β
		ELSE	α BOOLEAN V_FOUND,D_FOUND,CONTIN; CONTIN←TRUE;
			IF EQU(TOKEN,"WHERE") THEN
				WHILE ¬(V_FOUND ∧ D_FOUND) ∧ CONTIN DO
				α
				GET_TOKEN;
				IF V_FOUND ∧ EQU(TOKEN,"VELOCITY") THEN
					F_STATE(3011,"Multiple VELOCITY specification found in WITH clause.")
				ELSE IF EQU(TOKEN,"VELOCITY") THEN
					α PRINT("(VELOCITY "); GET_TOKEN;
					IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(3014,"Need = here.");
					SPACING←SPACING+1; P_EXP;
					SPACING←SPACING-1; PRINT(")");
					IF ¬CHECK_EXP_TYPE_DIMENS(vector_VALUE,VELOCITY_DIMENS,
						"Velocity expression") THEN
						α
						SPACING←SPACING-1; PRINT(")");
						F_STATE(3012,"Need a vector expression here.");
						β;
					V_FOUND←TRUE; GET_TOKEN;
					IF ¬EQU(TOKEN,",") THEN CONTIN←FALSE;
					β
				ELSE IF D_FOUND ∧ EQU(TOKEN,"DURATION") THEN
					F_STATE(3013,"Multiple DURATION specification found in WITH clause.")
				ELSE IF EQU(TOKEN,"DURATION") THEN
					α
					GET_TOKEN;
					IF ¬(EQU(TOKEN,"=") ∨ EQU(TOKEN,"<") ∨ EQU(TOKEN,">")) THEN
						ERROR_REJECT(3014,"Need =,<, or > here.");
					PRINT("(DURATION " & TOKEN & " ");
					SPACING←SPACING+1;P_EXP;SPACING←SPACING-1;
					PRINT(")");
					IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE, TIME_DIMENS,
						"DUARATION clause")THEN
						α SPACING←SPACING-1; PRINT(")");
						F_STATE(3012,"Need a scalar expression here.");
						β;
					D_FOUND←TRUE; GET_TOKEN;
					IF ¬EQU(TOKEN,",") THEN CONTIN←FALSE;
					β
				ELSE CONTIN←FALSE;
				β;
			IF EQU(TOKEN,"THEN") THEN
				α PRINT("(THEN"); SPACING←SPACING+1; P_STATEMENT; SPACING←SPACING-1;
				PRINT(")");GET_TOKEN;
				β;
			SPACING←SPACING-1; PRINT(")");
			β;
		β;

[directly_X]	α
		PRINT ("(ARRIVAL NILDEPROACH)");
		PRINT ("(DEPARTURE NILDEPROACH)");get_token;
		β;

[with_X]	α;
		GET_TOKEN;
		IF TYPE_OF_RES_WORD=approach_RES THEN
			α "APPROACH_RES"
			if equ(token,"ARRIVAL") 
			  then ERROR(-1,"Use APPROACH instead of ARRIVAL")
			  else if equ(token,"APPROACH") then token←"ARRIVAL";
			PRINT("(" & TOKEN); SPACING←SPACING+1; GET_TOKEN;
			IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(3022,"Need = here.");
			GET_TOKEN;
			IF EQU(TOKEN,"NILDEPROACH") THEN PRINT("NILDEPROACH")
			ELSE IF EQU(TOKEN,"DEPROACH") THEN
				α
				PRINT("(DEPR");	SPACING←SPACING+1; GET_TOKEN;
				IF ¬EQU(TOKEN,"(") THEN ERROR_REJECT(3019,"Need left paren here.");
				P_EXP;
				IF ¬CHECK_EXP_TYPE_DIMENS(frame_exp_VALUE,DISTANCE_DIMENS,
					"FRAME expression")
					THEN F_STATE(3020,"Need frame exp here.");
				GET_TOKEN;
				IF ¬EQU(TOKEN,")") THEN ERROR_REJECT(3021,"Need right paren here.");
				SPACING←SPACING-1; PRINT(")");
				β
			ELSE    α
				REJECT←TRUE;P_EXP;
				IF EXP_TYPE≠scalar_VALUE ∧ EXP_TYPE≠vector_VALUE ∧ EXP_TYPE≠trans_VALUE THEN
					ERROR(3018,"Type mismatch for DEPROACH.");
				β;
			SPACING←SPACING-1; PRINT(")");
			β "APPROACH_RES"
		ELSE IF EQU(TOKEN,"WOBBLE") THEN
			α "WOBBLE"
			GET_TOKEN;
			IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(3022, "Need = here.");
			PRINT("(WOBBLE "); SPACING←SPACING+1; P_EXP;
			IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE, ANGLE_DIMENS,
				"WOBBLE Clause")
				 THEN F_STATE(3012,"Need a scalar expression here.");
			SPACING←SPACING - 1;PRINT(")");
			β "WOBBLE"
		ELSE IF EQU(TOKEN,"FORCE") OR EQU(TOKEN, "TORQUE")
			THEN α REJECT←TRUE; P_CONDITION(2,NULL); β
		ELSE IF EQU(TOKEN,"DURATION") THEN
			α;
			GET_TOKEN;
			IF ¬(EQU(TOKEN,"=") ∨ EQU(TOKEN,"<") ∨ EQU(TOKEN,">")) THEN
				ERROR_REJECT(3014,"Need =,<, or > here.");
			PRINT("(DURATION " & TOKEN & " ");
			SPACING←SPACING+1; P_EXP; SPACING←SPACING-1; PRINT(")");
			IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,TIME_DIMENS,
				"DURATION clause")
				THEN F_STATE(3012,"Need a scalar expression here.");
			β
		ELSE IF EQU(TOKEN,"SPEED_FACTOR") THEN
			α
			GET_TOKEN;
			IF ¬EQU(TOKEN,"=") THEN
				ERROR_REJECT(3014,"Need = here.");
			P_EXP2;
			IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,NIL_DIMENS,
				"DURATION clause")
				THEN F_STATE(3012,"Need a scalar expression here.");
			PRINT("(SPEED_FACTOR  "& OUTEXPR & " )");
			β
		ELSE IF EQU(TOKEN,"FORCE_FRAME") THEN
			α
			STRING FFFF;
			GET_TOKEN;
			IF ¬EQU(TOKEN,"=") THEN
				ERROR_REJECT(3014,"Need = here.");
			P_EXP2;
			IF EXP_TYPE≠trans_VALUE and EXP_TYPE≠rot_VALUE THEN
				ERROR(3012,"Need a trans or rot expression here.");
			GET_TOKEN;
			IF ¬EQU(TOKEN,"IN") THEN error_REJECT(46,"Need IN here, will insert it");
			GET_TOKEN;
			IF TOKEN_EQU("STATION","TABLE","WORLD","FIXED") THEN
				FFFF←" #"
				ELSE IF TOKEN_EQU("HAND","BHAND","YHAND","MOVING")
					THEN FFFF←" ⊗" ELSE FFFF←NULL;
			PRINT("(FORCE_FRAME " & OUTEXPR & FFFF & " )");
			get_token;
			IF ¬TOKEN_EQU("COORD","COORDS","COORDINATED") THEN REJECT←TRUE;
			β
		ELSE F_STATE(3016,"Illegal WITH clause.");
		GET_TOKEN;
		β

		β;
	β;
FLUSH: INSIDE_CONDITION_MONITOR←ICMT;

β "P_CLAUSES";


STRING PROCEDURE T_GEN;
α
T_COUNT←T_COUNT+1;
RETURN("_T"&CVS(T_COUNT));
β;

! P_statement, F_state, modify_continue, modify_flush;

RECURSIVE PROCEDURE P_STATEMENT;
α "P_STATEMENT"
LABEL GLOBAL_RE_TRY;
LABEL FLUSH,TRY_AGAIN; STRING LABL; INTEGER LABEL_TYPE;
RPTR(DIMENS_EXPONENT) DIM_PTR;


PROCEDURE F_STATE(VALUE INTEGER PP,IP(-10000); VALUE STRING SP(NULL));
	α STRING CLOSE; INTEGER I;
	FOR I←1 STEP 1 UNTIL PP DO CLOSE←CLOSE&")";
	SPACING←SPACING-PP;
	PRINT(CLOSE);
	IF SP≠NULL THEN	ERROR(IP,SP&crlf&"Continue will flush statement.");
	WHILE ¬EQU(TOKEN,";") DO GET_TOKEN;
	REJECT←TRUE;
	NUM_OF_ERRORS_FLUSHED←NUM_OF_ERRORS_FLUSHED +1;
	GO TO FLUSH;
	β;

BOOLEAN PROCEDURE MODIFY_CONTINUE(INTEGER ERR_NO; STRING MESS);
	α CAN_MODIFY←TRUE; ERROR(ERR_NO,"Modifiable error, continue will try to recover"&crlf&MESS);
	IF MODIFIED
	  THEN α CURLINE←CURLINER←ERROR_BUFFER; GET_TOKEN; MODIFIED←FALSE; RETURN(TRUE); β
	  ELSE α CAN_MODIFY←FALSE; RETURN(MODIFIED) β;
	β;

BOOLEAN PROCEDURE MODIFY_FLUSH(INTEGER PP,ERR_NO; STRING MESS);
	α CAN_MODIFY←TRUE; ERROR(ERR_NO,"Modifiable error, continue will flush statement"&crlf&MESS);
	IF MODIFIED
	  THEN α CURLINE←CURLINER←ERROR_BUFFER; GET_TOKEN; MODIFIED←FALSE;RETURN(TRUE); β
	  ELSE α CAN_MODIFY←FALSE; F_STATE(PP); β;
	β;

BOOLEAN PROCEDURE MODIFY_BACKUP_FLUSH(INTEGER PP,ERR_NO; STRING MESS);
	α  BACKUP_MODIFY←TRUE; CAN_MODIFY←TRUE;
	ERROR(ERR_NO,"Modifiable error - type M to modify G to backup - continue will flush statement");
	IF MODIFIED
	  THEN α CURLINE←CURLINER←ERROR_BUFFER; GET_TOKEN;BACKUP_MODIFY←MODIFIED←FALSE;RETURN(TRUE);β
	  ELSE IF BACKUP_MODIFIED
	    THEN α CURLINE←CURLINER←ERROR_BUFFER←BACKUP_ERROR_BUFFER; GET_TOKEN;
			BACKUP_MODIFIED←FALSE; GOTO GLOBAL_RE_TRY; β
	    ELSE α CAN_MODIFY←BACKUP_MODIFY←FALSE; F_STATE(PP); β;
	β;
BOOLEAN PROCEDURE MODIFY_BACKUP_CONTINUE(INTEGER ERR_NO;STRING MESS);
	α BACKUP_MODIFY←TRUE;
	IF MODIFY_CONTINUE(ERR_NO, "Type M to modify, G to backup"&crlf&MESS)
	  THEN α BACKUP_MODIFY←FALSE; RETURN(TRUE); β
	  ELSE IF BACKUP_MODIFIED
	    THEN α BACKUP_MODIFIED←FALSE; CURLINE←CURLINER←ERROR_BUFFER←BACKUP_ERROR_BUFFER;
			GET_TOKEN; GOTO GLOBAL_RE_TRY; β
	    ELSE RETURN(FALSE);
	β;

DEFINE MODIFY_FLUSH_MACRO(str)=[ IF MODIFY_FLUSH(str) THEN GOTO RE_TRY ];

DEFINE MODIFY_CONTINUE_MACRO(str) = [ IF MODIFY_CONTINUE(str) THEN GOTO RE_TRY ];

DEFINE MODIFY_BACKUP_FLUSH_MACRO(str)= [IF MODIFY_BACKUP_FLUSH(str) THEN GOTO RE_TRY ];

DEFINE MODIFY_BACKUP_CONTINUE_MACRO(str)= [IF MODIFY_BACKUP_CONTINUE(str) THEN GOTO RE_TRY ];

!	begin_P,end_P, open_paren_P;

recursive procedure begin_P;
		α INTEGER SAVE_DEC_NUM,SAVE_MACRO_DEC_NUM,SAVE_DIMEN_DEC_NUM;
EXTERNAL RECORD!POINTER(ANY!CLASS) PROCEDURE $REC$(INTEGER OP;
					RECORD!POINTER(ANY!CLASS) R);
		record_pointer(any_class) rr;
		STRING B1,B2,E1,E2,TT;  STRING S, BLK_NAME, BLK_NAME_END;
		STRING UNUSED_S;
		IFC DEFIN_PRINT_SWITCH THENC STRING UNDEFINED_S;ENDC
		TT←"("&LABL;
		B1←B2←"BEGIN";
		E1←E2←"END";
		BLOCK_LEVEL←BLOCK_LEVEL+1;
		SAVE_DEC_NUM←DEC_NUM; DEC_NUM←0;
		SAVE_MACRO_DEC_NUM←MACRO_DEC_NUM; MACRO_DEC_NUM←0;
		SAVE_DIMEN_DEC_NUM←DIMEN_DEC_NUM; DIMEN_DEC_NUM←0;
		IF EQU(TOKEN,"BEGIN") THEN
			α B2←"CO"&B2;E2←"CO"&E2;TT←TT&"BL";β
		ELSE	α B1←"CO"&B1;E1←"CO"&E1;TT←TT&"CO";β;
		GET_TOKEN;
		IF TYPE_OF_TOKEN=STRING_TOKEN AND TOKEN_PTR=NULL_RECORD
		  THEN BLK_NAME←TOKEN
		  ELSE α BLK_NAME←NULL; REJECT←TRUE; β;
		PRINT(TT);
		SPACING←SPACING+1;
		WHILE ¬EQU(TOKEN,E1) DO
			α
			P_STATEMENT;
			GET_TOKEN;
			IF TYPE_OF_RES_WORD≠end_RES
			    THEN ERROR_REJECT(4,
				"Need semicolon before this token ⊂"&TOKEN&"⊃")
			ELSE IF EQU(TOKEN,E2) THEN
			    α
			    ERROR(5,"Block ends with " & E2 & cr
				& "Continue will view as "& E1);
			    TOKEN←E1;
			    β;
			β;
		GET_TOKEN;
		IF TYPE_OF_TOKEN=STRING_TOKEN AND TOKEN_PTR=NULL_RECORD
		  THEN BLK_NAME_END←TOKEN
		  ELSE α BLK_NAME_END←NULL; REJECT←TRUE; β;
		IF ¬(EQU(BLK_NAME,BLK_NAME_END) OR EQU(BLK_NAME_END,NULL)) 
		  THEN ERROR(600, "Block name at end does not agree with that at beginning.");
		UNUSED_S←NULL;
		IFC DEFIN_PRINT_SWITCH THENC UNDEFINED_S←NULL; ENDC;
		FOR I←1 STEP 1 UNTIL DEC_NUM DO
			α  STRING SS;
			SYMBOL_TABLE[HASH(SS←ID_LIST:NAME[TOP_ID],id_hasher)]
				← ID_LIST:NEXT[TOP_ID];
			IF ¬USED(TOP_ID) THEN UNUSED_S←UNUSED_S&CRLF& "⊂"&SS&
				"⊃   DECLARED ON PAGE "
				&CVS(ID_PAGE(TOP_ID))& "  LINE " 
				&CVS(ID_LINE(TOP_ID));
			IFC DEFIN_PRINT_SWITCH THENC

			IF ¬DEFINED(TOP_ID) THEN UNDEFINED_S←UNDEFINED_S&CRLF&"⊂"&SS&
				"⊃   DECLARED ON PAGE "
				&CVS(ID_PAGE(TOP_ID))& "  LINE " 
				&CVS(ID_LINE(TOP_ID));
			ENDC

			TOP_ID←ID_LIST:LAST[RR←TOP_ID];
			$REC$(5,RR);
			β;
		IF LENGTH(UNUSED_S)≠0 THEN UNUSED_S←UNUSED_S&
			CRLF & "			WERE NEVER USED";
		IFC DEFIN_PRINT_SWITCH THENC
		IF LENGTH(UNDEFINED_S)≠0 THEN UNUSED_S←UNUSED_S&CRLF & UNDEFINED_S & 
			CRLF & "			WERE NEVER DEFINED";
		ENDC

		IF LENGTH(UNUSED_S)≠0 THEN ERROR(-1,UNUSED_S);
		FOR I←1 STEP 1 UNTIL MACRO_DEC_NUM DO
			α
			MACRO_TABLE[HASH(MACRO_LIST:ID[TOP_MACRO],macro_hasher)]
				←MACRO_LIST:NEXT[TOP_MACRO];
			TOP_MACRO←MACRO_LIST:LAST[RR←TOP_MACRO];
			$REC$(5,RR);
			β;
		FOR I←1 STEP 1 UNTIL DIMEN_DEC_NUM DO
			α
			DIMENS_TABLE[HASH(DIMENS_EXPONENT:NAME[TOP_DIMENS],metric_hasher)]
				←DIMENS_EXPONENT:NEXT[TOP_DIMENS];
			TOP_DIMENS←DIMENS_EXPONENT:LAST[rr←TOP_DIMENS];
			$REC$(5,RR);
			β;
		DEC_NUM←SAVE_DEC_NUM;
		MACRO_DEC_NUM←SAVE_MACRO_DEC_NUM;
		DIMEN_DEC_NUM←SAVE_DIMEN_DEC_NUM;
		SPACING←SPACING-1;
		BLOCK_LEVEL←BLOCK_LEVEL-1;
		PRINT(")");
		β;

procedure end_P;
		α ! SEMICOLON FOUND - NOOP;
		REJECT←TRUE;
		β;

procedure open_paren_P;
		α INTEGER C; STRING TEMP;
		! LEFT PAREN FOUND - STAIGHT TRANSFER;
		C←1;
		TEMP←"(";
		WHILE C>0 DO
			α
			TEMP←TEMP&READ(paren_cr_break);
			IF BRCHAR="(" THEN C←C+1
			ELSE IF BRCHAR=")" THEN C←C-1 ELSE
				α
				PRINT(TEMP);
				TEMP←NULL;
				β;
			β;
		PRINT(TEMP);
		β;
!	define_P,declare_P,global_P;

procedure define_P;
	if ¬macro_handler then goto FLUSH;

FORWARD STRING PROCEDURE declare2_P;

procedure declare_P;
		α
		STRING BUILD_OUT;
	INSIDE_DECLARE_P←TRUE;
		BUILD_OUT←declare2_P;
	INSIDE_DECLARE_P←FALSE;
		IF TOKEN≠";" THEN ERROR(23,"Need semicolon here");
		REJECT←TRUE;
		PRINT(BUILD_OUT&")");
		β;

procedure global_P;
	α RPTR(DIMENS_EXPONENT) O_DIM; O_DIM←DIM_PTR;
	INSIDE_DECLARE_P←TRUE;
	PRINT("("&LABL&"GVAR");  SPACING←SPACING+1;  GET_TOKEN;
	WHILE ¬EQU(TOKEN,";") DO
	  α STRING BUILD_OUT;
	  IF TYPE_OF_TOKEN=metric_TOKEN
	    THEN IF O_DIM=NULL_RECORD 
	      THEN α DIM_PTR←TOKEN_PTR; GET_TOKEN; β
	      ELSE F_STATE(0,34,"Global declaration already declared")
	    ELSE DIM_PTR←O_DIM;
	  IF TYPE_OF_RES_WORD≠declare_RES THEN F_STATE(1,8, "Need variable type here.");
	  BUILD_OUT←declare2_P;
	  PRINT(BUILD_OUT&")");
	  β;
	REJECT←TRUE;
	SPACING←SPACING-1;
	PRINT(")");
	INSIDE_DECLARE_P←FALSE;
	β;

STRING procedure declare2_P;
		α
		STRING BUILD_OUT; INTEGER TYPE1;
		INTEGER SI;
		RPTR(DIMENS_EXPONENT) DIM; LABEL RE_TRY;
	procedure default_metric;
		CASE SPECIAL_INFO OF
			α
		[scalar_VALUE]
		[plane_VALUE]
		[trans_VALUE]
		[vector_VALUE]	DIM←NIL_DIMENS;
		[rot_VALUE]	DIM←ANGLE_DIMENS;
		[frame_VALUE]	DIM←DISTANCE_DIMENS;

		ELSE		DIM←NULL_RECORD
			β;


	procedure check_metric;
		IF SPECIAL_INFO≠VECTOR_VALUE AND special_info≠SCALAR_VALUE
			THEN  IF DIM≠null_record
			    THEN ERROR(3000,TOKEN &" cannot take arbitrary dimensions");

		SI←SPECIAL_INFO;
		ERROR_BUFFER←CURLINER;
		DIM←DIM_PTR;
	RE_TRY:
		check_metric;
		IF DIM=NULL_RECORD THEN DEFAULT_METRIC;
		BUILD_OUT←"("&LABL&DEC_NAME[SI];
		IF SI≠frame_VALUE
			THEN TYPE1←SPECIAL_INFO ELSE TYPE1←trans_VALUE;
		GET_TOKEN;

		WHILE ¬EQU(TOKEN,";") AND TYPE_OF_TOKEN≠metric_TOKEN AND TYPE_OF_RES_WORD≠DECLARE_RES DO
			α RPTR (ID_LIST) POINT;
			IF TYPE_OF_TOKEN=reserved_token
			  THEN  α WHILE TYPE_OF_TOKEN=reserved_token
				do α string s1; s1←"⊂"&TOKEN&"⊃ is a reserved word";
				     MODIFY_continue(3000,s1); β;
				β
			  ELSE IF BLOCK_LEVEL_OF_DEFN=BLOCK_LEVEL	
				THEN MODIFY_CONTINUE_MACRO([3001,"⊂"&TOKEN&"⊃ is multiply defined "
					&"in this block."])
			  ELSE IF BLOCK_LEVEL_OF_DEFN=0
				THEN MODIFY_CONTINUE_MACRO([3002,"⊂"&TOKEN&"⊃ is a predeclared constant."]);

			BUILD_OUT←BUILD_OUT&" "&TOKEN;
			POINT←INSERT_ENTRY(TOKEN,ID_TYPE_TABLE);
			ID_LIST:TYPE[POINT]←TYPE1;
			ID_LIST:DIMEN[POINT]←DIM;
			GET_TOKEN;
			IF EQU(TOKEN,";") OR TYPE_OF_TOKEN=metric_TOKEN OR TYPE_OF_RES_WORD=declare_RES
			  THEN REJECT←TRUE
			ELSE IF ¬EQU(TOKEN,",") THEN
					ERROR_REJECT(7,"Missing comma.");
			GET_TOKEN;
			β;
		return(build_out);
		β;

!	if_P, plan_P, while_P;

procedure if_P;
		α ! IF STATEMENT FOUND;
		IF PLAN_STATEMENT THEN PRINT("("&LABL&"CIF") ELSE PRINT("("&LABL&"IF");
		PLAN_STATEMENT←FALSE;
		SPACING←SPACING+1;
		P_EXP;
		IF EXP_TYPE≠boole_VALUE AND EXP_TYPE≠scalar_VALUE
			THEN F_STATE(1,10,"Conditional for IF must be boolean");
		GET_TOKEN;
		IF ¬EQU(TOKEN,"THEN") THEN
			ERROR_REJECT(9,"Missing THEN.  Continue will insert it.");
		P_STATEMENT;
		GET_TOKEN;
		IF EQU(TOKEN,"ELSE") THEN P_STATEMENT ELSE REJECT←TRUE;
		SPACING←SPACING-1;
		PRINT(")");
		β;

procedure plan_P;
		α  ! PLAN STATEMENT FOUND;
		LABEL RE_TRY;
		ERROR_BUFFER←CURLINER;
		GET_TOKEN;
	RE_TRY:
		IF ¬(EQU(TOKEN,"IF") OR EQU(TOKEN,"WRITE") OR EQU(TOKEN,"ERROR")
			OR EQU(TOKEN,"FOREACH")) THEN MODIFY_FLUSH_MACRO([0,11,"Illegal token to "&
			"follow PLAN: "&TOKEN]);
		REJECT←TRUE;
		PLAN_STATEMENT←TRUE;
		P_STATEMENT;
		PLAN_STATEMENT←FALSE;
		β;

procedure while_P;
		α ! WHILE STATEMENT FOUND;
		PRINT("("&LABL&"WH");
		SPACING←SPACING+1;
		P_EXP;
		IF EXP_TYPE≠boole_VALUE AND EXP_TYPE≠scalar_VALUE
			THEN F_STATE(0,11,"Conditional for WHILE must be boolean or sclar.");
		GET_TOKEN;
		IF ¬EQU(TOKEN,"DO") THEN
			ERROR_REJECT(12,"Missing DO.  Continue will insert it.");
		P_STATEMENT;
		SPACING←SPACING-1;
		PRINT(")");
		β;
!	for_P;

procedure for_P;
		α RPTR(ID_LIST) POINT;RPTR(DIMENS_EXPONENT)POINTD; ! FOR STATEMENT FOUND;
		LABEL RE_TRY;
		ERROR_BUFFER←CURLINER;
		GET_TOKEN;
	RE_TRY:
 		IF TYPE_OF_TOKEN=undeclared_token
		  THEN
		  α	MODIFY_BACKUP_CONTINUE_MACRO([0,"Undeclared variable "&TOKEN&" declared a scalar"]);
			POINT←INSERT_ENTRY(TOKEN,ID_TYPE_TABLE);
			ID_LIST:TYPE[POINT]←scalar_VALUE;
			ID_LIST:DIMEN[POINT]←NIL_DIMENS;
			PRINT("(SVAR "&TOKEN&")");
		  β
		ELSE
		  α	POINT←TOKEN_PTR;
			IF TYPE_OF_TOKEN≠id_token OR ID_TYPE≠scalar_value
			  THEN MODIFY_BACKUP_CONTINUE_MACRO([1300, "Need scalar ID here."]);
		  β;
		PRINT("("&LABL&"FO "&ID_LIST:NAME[POINT]);
		POINTD←ID_LIST:DIMEN[POINT];
		USE(POINT); DEFIN(POINT);

		SPACING←SPACING+1;
		GET_TOKEN;
		IF ¬EQU(TOKEN,"←") THEN
			ERROR_REJECT(14,"Need left arrow here for FOR statement.");
		P_EXP;
		IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,POINTD,
			"DUMMY variable in FOR statement") 
			THEN ERROR_REJECT(15,"Need scalar value here.");
		GET_TOKEN;
		IF ¬EQU(TOKEN,"STEP") THEN
			ERROR_REJECT(16,"Need STEP here.");
		P_EXP;
		IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,POINTD,
			"DUMMY variable in FOR statement") 
			THEN ERROR_REJECT(15,"Need scalar value here.");
		GET_TOKEN;
		IF ¬EQU(TOKEN,"UNTIL") THEN
			ERROR_REJECT(17,"Need UNTIL here.");
		P_EXP;
		IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,POINTD,
			"DUMMY variable in FOR statement") 
			THEN ERROR_REJECT(15,"Need scalar value here.");
		GET_TOKEN;
		IF ¬EQU(TOKEN,"DO") THEN
			ERROR_REJECT(18,"Need DO here.");
		P_STATEMENT;
		SPACING←SPACING-1;
		PRINT(")");
		β;
!	move_P;

procedure move_P;
		α RPTR(ID_LIST) POINT; ! MOVE STATEMENT FOUND;
		LABEL RE_TRY;
		ERROR_BUFFER←CURLINER;
		GET_TOKEN;
	RE_TRY:
		IF TYPE_OF_TOKEN≠ID_TOKEN OR ID_TYPE≠TRANS_VALUE
		  THEN MODIFY_BACKUP_CONTINUE_MACRO([19,"Need frame ID here."]);
		CURRENT_FRAME←TOKEN;
		PRINT("("&LABL&"MO "&TOKEN);
		SPACING←SPACING+1;
		IF ¬CHECK_NEXT_TOKEN(19,NULL,"TO") THEN REJECT←TRUE;
		P_EXP;
		IF ¬CHECK_EXP_TYPE_DIMENS(trans_VALUE,DISTANCE_DIMENS, "FRAME Expression")
			THEN ERROR_REJECT(20,"Need either a FRAME or TRANSFORM expression here.");
		CURRENT_FRAME←null;
		P_CLAUSES;
		SPACING←SPACING-1;
		PRINT(")");
		β;
!	affix_p,unfix_p;

procedure affix_p;
	α STRING SAVE1,SAVE2,TRANS; RPTR(ID_LIST) POINT;
	! AFFIX STATEMENT FOUND;
	LABEL RE_TRY;
	ERROR_BUFFER←CURLINER;
	GET_TOKEN;
RE_TRY:
	IF TYPE_OF_TOKEN≠ID_TOKEN OR ID_TYPE≠TRANS_VALUE
	  THEN α MODIFY_BACKUP_CONTINUE_MACRO([19,"Need frame ID here."]) ELSE
			POINT←INSERT_ENTRY(TOKEN,ID_TYPE_TABLE); β
	  ELSE POINT←TOKEN_PTR;
	DEFIN(POINT); AFFIX(POINT);
	CURRENT_FRAME←SAVE1←TOKEN;
	IF ¬CHECK_NEXT_TOKEN(21,NULL,"TO") THEN REJECT←TRUE;
	GET_TOKEN;
	IF TYPE_OF_TOKEN≠id_token 
	  THEN POINT←ERROR_REJECT(13,"Need frame ID here.")
	  ELSE α POINT←TOKEN_PTR; IF ID_TYPE≠trans_VALUE THEN ERROR(19,"Need frame ID here."); β;
	IF ¬DEFINED(POINT) THEN UNDEFINED_VAR;
	AFFIX(POINT);
	SAVE2←TOKEN; GET_TOKEN;
	IF EQU(TOKEN,"BY") 
	  THEN
	  α GET_TOKEN;
	  IF TYPE_OF_TOKEN≠id_token 
	    THEN POINT←ERROR(13,"Need frame ID here.")
	    ELSE
	    α  POINT←TOKEN_PTR;
	    IF ID_TYPE≠trans_VALUE
	      THEN ERROR(19,"Need frame ID here.");
	    β;
	  IF ¬DEFINED(POINT) THEN UNDEFINED_VAR;
	  TRANS←TOKEN;
	  β
	  ELSE α TRANS←T_GEN; PRINT("(TVAR "&TRANS&")"); REJECT←TRUE; β;
	GET_TOKEN;
	IF EQU(TOKEN,"AT")
	  THEN
	  α PRINT("("&LABL&"AFFIX "&SAVE1&" "&SAVE2&" "&TRANS);
	  SPACING←SPACING+1; P_EXP; GET_TOKEN;
	  IF EQU(TOKEN,"RIGIDLY")
	    THEN PRINT("RIGIDLY)")
	    ELSE IF EQU(TOKEN,"NONRIGIDLY")
	      THEN PRINT("NONRIGIDLY)")
	      ELSE α PRINT("NONRIGIDLY)");REJECT←TRUE; β;
	  SPACING←SPACING-1;
	  β
	  ELSE
	  α STRING HOW;
	  IF TOKEN_EQU("RIGIDLY","NONRIGIDLY")
	    THEN HOW←TOKEN 
	    ELSE α HOW←"NONRIGIDLY";REJECT←TRUE;β;
	  PRINT("("&LABL&"AFFIX "&SAVE1&" "&SAVE2&" "&TRANS&" () "&HOW&")");
	  β;
	CURRENT_FRAME←null;
	β;

procedure unfix_P;
	α STRING SAVE1;	RPTR(ID_LIST) POINT; ! UNAFFIX STATEMENT FOUND;
	LABEL RE_TRY;
	ERROR_BUFFER←CURLINER;
RE_TRY:
	GET_TOKEN;
	IF TYPE_OF_TOKEN≠ID_TOKEN OR ID_TYPE≠TRANS_VALUE
	  THEN α MODIFY_BACKUP_CONTINUE_MACRO([19,"Need frame ID here."]) ELSE
			POINT←INSERT_ENTRY(TOKEN,ID_TYPE_TABLE); β
	  ELSE POINT←TOKEN_PTR;
	IF ¬DEFINED(POINT) THEN UNDEFINED_VAR;
	IF ¬AFFIXED(POINT) THEN UNAFFIXED_VAR;
	CURRENT_FRAME←SAVE1←TOKEN;
	IF ¬CHECK_NEXT_TOKEN(20,NULL,"FROM") THEN REJECT←TRUE;
	GET_TOKEN;
	IF TYPE_OF_TOKEN≠id_token
	  THEN POINT←ERROR(13,"Need frame ID here.")
	  ELSE IF ID_TYPE≠trans_VALUE
	    THEN ERROR(19,"Need frame ID here.");
	IF ¬DEFINED(POINT) THEN UNDEFINED_VAR;
	PRINT("("&LABL&"UNFIX"&" "&SAVE1&" "&TOKEN&")"); CURRENT_FRAME←null;
	β;
!	signal_p, wait_p;

procedure signal_wait_P(boolean ws);
		α STRING WS_SIGN; LABEL RE_TRY;
		ERROR_BUFFER←CURLINER;
		IF WS THEN WS_SIGN←" -)" ELSE WS_SIGN←" +)";
		GET_TOKEN;
	RE_TRY:
 		IF TYPE_OF_TOKEN≠id_token OR ID_TYPE≠event_VALUE
			THEN MODIFY_BACKUP_CONTINUE_MACRO([19,"Need event ID here."]);
		PRINT("("&LABL&"EV "&TOKEN&WS_SIGN);
		DEFIN(TOKEN_PTR);
		β;

procedure signal_P;
	signal_wait_P(FALSE);	! SIGNAL STATEMENT FOUND;

procedure wait_P;
	signal_wait_P(TRUE);	! WAIT STATEMENT FOUND;
!	when_P;

procedure when_P;
	α RPTR (ID_LIST) POINT; STRING VAR, ALSO_OP, CHG_LAB;
	BOOLEAN TEMP;  LABEL RE_TRY;
	! WHEN STATEMENT FOUND;
	ERROR_BUFFER←CURLINER;
	GET_TOKEN;
    RE_TRY:
	IF ¬EQU(TOKEN,"CHANGING") THEN
		ERROR_REJECT(30,"Need word CHANGING here for a WHEN CHANGING statement."&
			"  Continue will insert it.");
	GET_TOKEN;
	IF TYPE_OF_TOKEN=undeclared_token THEN MODIFY_BACKUP_CONTINUE_MACRO([31,"Undefined ID"]);
	VAR←TOKEN; GET_TOKEN;
	IF EQU(TOKEN,"ALSO")
	  THEN ALSO_OP←"ALSO_DO"
	  ELSE IF EQU(TOKEN,"DON'T")
	    THEN ALSO_OP←"ALSO_DON'T"
	    ELSE IF EQU(TOKEN,"ONLY")
	      THEN  ALSO_OP←"ALSO_ONLY"
	      ELSE MODIFY_CONTINUE_MACRO([32,"Illegal ALSO_OP"]);
	GET_TOKEN;
	IF ¬EQU(TOKEN,"DO") THEN ERROR_REJECT(33,"Need DO here.  Continue will insert it.");
	GET_TOKEN;
	IF TYPE_OF_TOKEN≠id_token
	  THEN TEMP←TRUE
	  ELSE IF ID_TYPE=ch_label_VALUE 
	    THEN TEMP←FALSE
! ?????;    ELSE IF ID_TYPE>world_VALUE
	      THEN
	      α ERROR(34,"Can only handle CH_LABEL here.  Continue while delete this label.");
	      TEMP←TRUE;
	      β
	      ELSE TEMP←TRUE;
	IF TEMP
	  THEN
	  α CHG_LAB←T_GEN; PRINT("(CHGLAB "&CHG_LAB&")"); REJECT←TRUE;
	  CHANGER_HEAD←CHG_LAB&" CHG ";
	  β
	  ELSE
	  α CHG_LAB←TOKEN; GET_TOKEN;
	  IF EQU(TOKEN,":")
	    THEN α TEMP←TRUE; CHANGER_HEAD←CHG_LAB&" CHG "; β
	    ELSE α REJECT←TRUE;	PRINT("("&ALSO_OP&" "&VAR&" "&CHG_LAB&")"); β;
	  β;
	IF TEMP
	  THEN
	  α PRINT("("&ALSO_OP&" "&VAR);	SPACING←SPACING+1; P_STATEMENT;
	  SPACING←SPACING-1; PRINT(")");
	  β;
	β;
!	dump_P;

procedure dump_P;
	α RPTR (ID_LIST) POINT; STRING IDSTRING;
	! DUMP STATEMENT FOUND;
	IDSTRING←null; GET_TOKEN;
	IF ID_TYPE=world_VALUE 
	  THEN PRINT("("&LABL&"DBD "&TOKEN&")")
	  ELSE
	  α
	  DO α
	    IF TYPE_OF_TOKEN≠ID_TOKEN OR ID_TYPE>event_VALUE THEN ERROR(35,"Undefined ID.");
	    IDSTRING←IDSTRING&" "&TOKEN;GET_TOKEN;
	    IF ¬EQU(TOKEN,"IN") OR TOKEN≠";"
	      THEN 
	      α IF TOKEN≠"," 
		THEN ERROR_REJECT(36, "Need comma or IN or ; here. Continue will insert it.");
	      GET_TOKEN;
	      β;
	    β
	  UNTIL EQU(TOKEN,"IN") OR EQU(TOKEN,";");
	  IF EQU(TOKEN,"IN")
	    THEN 
	    α GET_TOKEN;
	    IF ID_TYPE≠world_VALUE
	      THEN ERROR(37,"Need a world ID here.")
	      ELSE IDSTRING←IDSTRING & " " & TOKEN;
	    β;
	  PRINT ("("&LABL&"PVL "&IDSTRING&")");
	  β;
	β;
!	assert_P;

procedure assert_P;
	α RPTR (ID_LIST) POINT; STRING IDSTRING,COM;INTEGER VAR_TYPE;
	! ASSERT OR DENY STATEMENT FOUND;
	COM←TOKEN; GET_TOKEN;
	IF EQU(TOKEN,"FORM")
	  THEN
	  α IDSTRING←null; GET_TOKEN;
	  IF ¬EQU(TOKEN,"(")
	    THEN ERROR_REJECT(37,"Need left paren here.  Continue will insert it.");
	  WHILE ¬EQU(TOKEN,")")
	  DO α
	    GET_TOKEN; IDSTRING←IDSTRING&TOKEN&" "; GET_TOKEN;
	    IF ¬EQU(TOKEN,")") AND ¬EQU(TOKEN,",")
	      THEN ERROR_REJECT(38,"Need either comma or right paren here."&
				"  Continue will insert a comma.");
	    β;
	  GET_TOKEN;
	  IF EQU(TOKEN,"IN")
	    THEN
	    α GET_TOKEN;
	    IF ID_TYPE≠world_VALUE THEN ERROR(39,"Need world ID here.");
	    PRINT("("&LABL&COM&" (SF "&IDSTRING&") "&TOKEN&")");
	    β
	    ELSE α REJECT←TRUE; PRINT("("&LABL&COM&" (SF "&IDSTRING&"))"); β;
	  β
	  ELSE
	  α STRING VAR;
! ?????;  IF TYPE_OF_TOKEN≠ID_TOKEN OR ID_TYPE>trans_VALUE 
	    THEN
	    α ERROR(40,"Need variable ID here.");
	    POINT←SYMBOL_TABLE[HASH("GARB_ID",id_hasher)];
	    β
	    ELSE POINT←TOKEN_PTR;
	  VAR_TYPE←ID_TYPE;GET_TOKEN;
	  IF ¬EQU(TOKEN,"=")
	    THEN ERROR(41,"Sorry, can only handle equality right now.");
	  PRINT("("&LABL&COM&" (AF "&VAR&" = "); SPACING←SPACING+1;
	  P_EXP; SPACING←SPACING-1;
	  IF VAR_TYPE≠EXP_TYPE THEN ERROR(42,"Types don't match on equality test.");
	  GET_TOKEN;
	  IF EQU(TOKEN,"IN")
	    THEN
	    α GET_TOKEN;
	    IF TYPE_OF_TOKEN≠ID_TOKEN OR ID_TYPE≠world_VALUE THEN ERROR(39,"Need world ID here.");
	    PRINT(") "&TOKEN&")");
	    β
	    ELSE α REJECT←TRUE; PRINT("))"); β;
	  β;
	β;
!	on_P, reference_P;

procedure on_P;
		α RPTR (ID_LIST) POINT;
		! CONDITION MONITER FOUND;
		BOOLEAN ICMT;
		ICMT←INSIDE_CONDITION_MONITOR;
		IF ¬EQU(LABL,null) 
		  THEN 
		    IF LABEL_TYPE≠cm_label_VALUE
		      THEN
			α
			ERROR(43,"Must have condition monitor label if any label is uesed.  Continue will flush label.");
			LABL←null;
			β;
		INSIDE_CONDITION_MONITOR←TRUE;
		IF EQU(TOKEN,"ON") THEN P_CONDITION(0,"( "&LABL&"ON +")
			ELSE α CHECK_NEXT_TOKEN(27,null,"ON"); P_CONDITION(0,"("&LABL&"ON -"); β;
		SPACING←SPACING+1;
		GET_TOKEN;
		IF ¬EQU(TOKEN,"DO") THEN
			ERROR_REJECT(45,"Need DO here.  Continue will insert it.");
		P_STATEMENT;
			INSIDE_CONDITION_MONITOR←ICMT;
		SPACING←SPACING-1;
		PRINT(")");
		β;

procedure reference_P;
		α RPTR (ID_LIST) POINT; ! NEW WORLD DEF;
		GET_TOKEN;
		IF ¬EQU(TOKEN,"POINT") THEN
			ERROR_REJECT(46,"Need POINT here for a REFERENCE POINT statement.");
		GET_TOKEN;
		POINT←CHECK_ENTRY(TOKEN,ID_TYPE_TABLE);
		IF POINT=NULL OR ID_LIST:TYPE[POINT]≠world_VALUE THEN
			ERROR(47,"Need a world variable here.");
		PRINT("("&LABL&"NW "&TOKEN&")");
		β;

!	open_P,center_P,stop_P,enable_P,disable_P;
procedure open_P;
		α STRING HAND; ! OPEN/CLOSE FOUND;
		RPTR (ID_LIST) POINT;
		check_next_token(48,"Unknown hand in OPEN/CLOSE statement",
			"BHAND","YHAND"); HAND←TOKEN;
		check_next_token(49,NULL,"TO");
		PRINT("("&LABL&"MO "&HAND);
		SPACING←SPACING+1;
		P_EXP;
		IF ¬CHECK_EXP_TYPE_DIMENS(scalar_VALUE,DISTANCE_DIMENS,
			"OPEN/CLOSE statement")
			THEN ERROR(121,"Need scalar quantity here.");
		SPACING←SPACING-1;
		PRINT(")");
		β;

procedure center_P;
		IF check_next_token(50,"Unknown arm in CENTER statement",
			"BARM","YARM") then PRINT("("&LABL&"CENTER "&TOKEN&")");

procedure stop_P;
		α ! STOP FOUND;
		RPTR(ID_LIST) R1;
		GET_TOKEN;
		IF (R1←CHECK_ENTRY(TOKEN,ID_TYPE_TABLE))≠NULL_RECORD
		    THEN α  IF (ID_LIST:TYPE[R1]≠TRANS_VALUE)
				THEN ERROR(49, "Trying to stop a non-frame");
			    PRINT("("&LABL&"STOP "&TOKEN&")");
			 β
		    ELSE α IF TYPE_OF_TOKEN = undeclared_token 
				THEN PRINT("("&LABL&" STOP "&TOKEN&")")
				ELSE α REJECT←TRUE; PRINT("("&LABL&"STOP )");β;
			 β;
		β;

procedure denable_P(boolean en);
		α ! ENABLE/DISABLE found;
		STRING S1;
		s1← "(" & LABL & " CMABLE " & ( if en then " + " else " - ");
		GET_TOKEN;
		IF ID_TYPE = CM_LABEL_VALUE
		   THEN α S1← S1&TOKEN&" )"; USE(TOKEN_PTR); β
		   ELSE  α REJECT←TRUE; IF INSIDE_CONDITION_MONITOR
		     THEN  S1 ← S1 & " )"
		     ELSE ERROR(123, "Need CM label here.");
		     β;
		PRINT(S1);
		β;

procedure enable_P;
	denable_P(true);

procedure disable_P;
	denable_P(false);

!	require_P;
procedure require_P;
		α ! REQUIRE STATEMENT FOUND;
		LABEL RE_TRY;
		ERROR_BUFFER←CURLINER;
		GET_TOKEN;
	RE_TRY: 
		IF ¬(require_beg ≤ TYPE_OF_RES_WORD ≤ require_end)
		    THEN α IF MODIFY_FLUSH(0,51,"Illegal token after REQUIRE") THEN GOTO RE_TRY; β
		    ELSE
			CASE TYPE_OF_RES_WORD - require_beg OF
			α

[source_file_X]		α 
			string new_file;
			GET_TOKEN;
			new_file←token;
			GET_TOKEN;
			REJECT←TRUE;
			TOP_SOURCE←PUSH_SOURCE_LIST(TOP_SOURCE);
			SOURCE_LIST:NUM[TOP_SOURCE]←0;
			WHILE ¬ got_input(PRESENT_file←open_new_file(new_file)) 
			  DO α ERROR(55,"FILE NOT AVAILABLE");
				new_file←infile; β;
			CHANIN←file:chn[PRESENT_FILE];
			if equ(file:device[PRESENT_file],"TTY") 
			  then
			  α 
			  CHECK_WANT_COPY;
			  OUTSTR(CRLF&"Enter input through the keyboard. Terminate with<CONTROL><META><LF>"&CRLF);
			  β
			  else
			  α if typed_page_num then outstr(crlf);
				outstr(infile & " 1");
			  β;
			β;

[delimiters_X]		α RPTR (DELIMITER_LIST) NEW_DEL;
			GET_TOKEN;
			IF TYPE_OF_TOKEN≠string_token OR LENGTH(TOKEN)≠2
			  THEN MODIFY_BACKUP_FLUSH_MACRO([0,53,"Need string of length 2."]);
			push_delimiters(token);
			β;

[unstack_delimiters_X]	IF NULL=TOP_DELIMITERS
			    THEN F_STATE(0,54,"Sorry, delimiter stack empty.")
			    ELSE TOP_DELIMITERS←DELIMITER_LIST:NEXT[TOP_DELIMITERS];

[replace_delimiters_X]	α
			GET_TOKEN;
			IF TYPE_OF_TOKEN≠string_token OR LENGTH(TOKEN)≠2
			  THEN MODIFY_BACKUP_FLUSH_MACRO([0,53,"Need string of length 2."]);
			delimiter_list:d1[top_delimiters] ← lop(token);
			delimiter_list:d2[top_delimiters] ← lop(token);
			β;
		
[message_x]		α
			GET_TOKEN;
			IF TYPE_OF_TOKEN≠string_token
			  THEN MODIFY_BACKUP_FLUSH_MACRO([0,52,"Need string here"]);
			OUTSTR(TOKEN);
			β;

[error_modes_x]		α
			INTEGER I,L;  STRING S; BOOLEAN T;
			GET_TOKEN;
			IF TYPE_OF_TOKEN≠string_token
			  THEN MODIFY_BACKUP_FLUSH_MACRO([0,52,"Need string here"]);
			L←length(token);
			FOR I←1 STEP 1 UNTIL L DO 
				α S←TOKEN[I FOR 1];
				IF EQU(S,"-") THEN α I←I+1;
							S←TOKEN[I FOR 1];
							T←FALSE;
						   β
						ELSE T←TRUE;
				IF EQU(S,"L")
				THEN α	COMPILE_LOGGING←T; IF ¬T THEN LOGGING←T; β
				ELSE IF EQU(S,"A")
				     THEN AUTO_PROCEED←T
				     ELSE IF EQU(S,"F")
					  THEN STRICT_DIMEN_CHECK←T
					  ELSE IF EQU(S,"M")
					      THEN PROMPT_FOR_MODIFIABLE_ERROR_ONLY←T
					       ELSE ERROR(0,"Error_mode " & s & " undefined.");
				β;
			β;

[compiler_switches_x]		α
			INTEGER I,L,I1; STRING S; BOOLEAN NON_EXIST_SWITCH,BAIL_WANTED;
			GET_TOKEN;
			IF TYPE_OF_TOKEN≠string_token
				THEN F_STATE(0,52,"Need string here.");
			L←LENGTH(TOKEN);
			FOR I←1 STEP 1 UNTIL L DO
				α  
				S←TOKEN[I FOR 1];
				NON_EXIST_SWITCH←TRUE;
				FOR I1←0 STEP 1 UNTIL SWITCH_MAX DO
					IF EQU(S,SWITCH_NAME[I1]) THEN
						α SWITCH_SETTING[I1]←TRUE;
						IF I1=B_X THEN BAIL_WANTED←TRUE;
						NON_EXIST_SWITCH←FALSE;
						β;
				IF NON_EXIST_SWITCH THEN
					ERROR(0,"Switch " & S & " unknown");
				β;
			IF BAIL_WANTED
			THEN α
				IFC debug_compile
				THENC OUTSTR(crlf & "BAIL requested"); BAIL
				ELSEC OUTSTR("Sorry, Bail not loaded." & crlf)
			        ENDC;
			     β;
			β;

[comment_delimiters_x]	α
			STRING CLOSE_BRACE;
			GET_TOKEN;
			IF TYPE_OF_TOKEN≠string_token OR LENGTH(TOKEN)≠2
			  THEN MODIFY_BACKUP_FLUSH_MACRO([0,53,"Need string of length 2."]) ;
			OPEN_BRACE←TOKEN[1 FOR 1];
			CLOSE_BRACE←TOKEN[2 FOR 1];
			SETBREAK(close_brace_break, CLOSE_BRACE, NULL, "ISK");
			add_to_table1(token);
			β;

[bail_X]		α
			IFC debug_compile
				THENC OUTSTR(crlf & "BAIL requested"); BAIL
				ELSEC OUTSTR("Sorry, Bail not loaded." & crlf)
			ENDC;
			β

			β;
		β;
!	dimension_P;
procedure dimension_P;
	α "dimen_p"
	! DIMENSION STATEMENT FOUND;
	STRING DIMEN_NAME;LABEL RE_TRY;
	RPTR(DIMENS_EXPONENT) D1,temp;
	BOOLEAN TOP; INTEGER COUNT;
	RCLASS DIMEN_REDUCE(STRING OP; RPTR (DIMEN_REDUCE) LAST;
		RPTR (DIMENS_EXPONENT) DIM_PTR);
	RPTR (DIMEN_REDUCE) CURRENT,CUR2;
	string cur_op;
	ERROR_BUFFER←CURLINER;
RE_TRY:
	TOP←TRUE;  COUNT←0;
	CUR_OP←NULL;
	GET_TOKEN;
	IF TYPE_OF_TOKEN≠undeclared_token AND BLOCK_LEVEL_OF_DEFN=BLOCK_LEVEL
	  THEN MODIFY_BACKUP_FLUSH_MACRO([0,61,"Can only use unreserved ID's for dimensions."]);
	DIMEN_NAME←TOKEN;

	GET_TOKEN;
	IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(62,"Need = here.");
	GET_TOKEN;

	CURRENT←NULL_RECORD;
	DIM_PTR←NIL_DIMENS;
	WHILE TOKEN≠";" DO
		α
		WHILE EQU(TOKEN,"INV") OR EQU(TOKEN,"(") OR EQU(TOKEN , ")") OR
			EQU(TOKEN,"*") OR EQU(TOKEN,"/") DO
			α
			IF EQU(TOKEN,"INV") THEN
				α CUR2←NEW_RECORD(DIMEN_REDUCE);
				DIMEN_REDUCE:OP[CUR2]←"INV";
				DIMEN_REDUCE:LAST[CUR2]←CURRENT;
				DIMEN_REDUCE:DIM_PTR[CUR2]←DIM_PTR;
				DIM_PTR←NIL_DIMENS;
				CURRENT←CUR2;
				GET_TOKEN;
				IF ¬EQU(TOKEN,"(") THEN ERROR_REJECT(63,"Need ( here");
				COUNT←COUNT+1;
				GET_TOKEN;
				IF EQU(TOKEN,"/") OR EQU(TOKEN,"*") THEN ERROR
					(64, "Can`t have "&token&" after (.");
				β
			ELSE IF EQU(TOKEN,"(") THEN
				α CUR2←NEW_RECORD(DIMEN_REDUCE);
				DIMEN_REDUCE:OP[CUR2]←CUR_OP;
				cur_op←null;
				COUNT←COUNT+1;
				DIMEN_REDUCE:LAST[CUR2]←CURRENT;
				DIMEN_REDUCE:DIM_PTR[CUR2]←DIM_PTR;
				DIM_PTR←NIL_DIMENS;
				CURRENT←CUR2;
				GET_TOKEN;
				IF EQU(TOKEN,"/") OR EQU(TOKEN,"*") THEN ERROR
					(64, "Can`t have "&token&" after (.");
				β
			ELSE IF EQU(TOKEN, "*") or equ(token,"/") THEN
				α
				CUR_OP←TOKEN;
				GET_TOKEN;
				IF EQU(TOKEN,"*") OR EQU(TOKEN,"/") OR EQU(TOKEN,")")
					THEN ERROR(64, "Can't have "&token&" after "&cur_op);
				β
			ELSE IF EQU(TOKEN,")") THEN
				α
				if count≤0 then F_STATE(0,65, "Right paren without left paren.")else
				IF EQU(DIMEN_REDUCE:OP[CURRENT],"*") THEN
					DIM_PTR←MULTIPLY_DIMENSIONS(DIM_PTR,
						DIMEN_REDUCE:DIM_PTR[CURRENT])
				ELSE IF EQU(DIMEN_REDUCE:OP[CURRENT],"/") THEN
					DIM_PTR←DIVIDE_DIMENSIONS(
						DIMEN_REDUCE:DIM_PTR[CURRENT],DIM_PTR)
				ELSE IF EQU(DIMEN_REDUCE:OP[CURRENT],"INV") THEN
					DIM_PTR←INVERSE_DIMENSIONS(DIM_PTR)
				ELSE IF DIMEN_REDUCE:OP[CURRENT]≠NULL THEN 
					ERROR(66, "Can't do this");
				CURRENT←DIMEN_REDUCE:LAST[CURRENT];
				COUNT←COUNT-1;
				IF CURRENT≠NULL_RECORD THEN cur_op←dimen_reduce:op[current]
					ELSE CUR_OP←NULL;
				GET_TOKEN;
				IF EQU(TOKEN,"(") THEN ERROR(64,"Can't have ( after )");
				β;
			β;
		IF TOKEN≠";" THEN
			α
			D1←CHECK_ENTRY(TOKEN,DIMENSION_TYPE_TABLE);
			IF D1=NULL_RECORD THEN ERROR(0000, TOKEN & "not declared.")
			ELSE IF EQU(CUR_OP,"*") THEN
				DIM_PTR←MULTIPLY_DIMENSIONS(DIM_PTR,D1)
			ELSE IF EQU(CUR_OP,"/") THEN
				DIM_PTR←DIVIDE_DIMENSIONS(DIM_PTR,D1)
			ELSE IF CUR_OP=NULL THEN
				DIM_PTR←D1
			ELSE ERROR(1234, "Can't do this");
			CUR_OP←NULL;
			GET_TOKEN;
			β;
		β;

	IF COUNT≠0 THEN MODIFY_FLUSH(0,65,"Parens don't match.");
	if current≠ null_record then error(1112,"Incomplete evaluation");
	D1←DIM_PTR;
	IF D1=NULL OR D1=NIL_DIMENS THEN
		insert_entry(DIMEN_NAME,DIMENSION_TYPE_TABLE)
		ELSE INSERT_ENTRY(DIMEN_NAME,DIMENSION_TYPE_TABLE,D1);
	REJECT←TRUE;
	β "dimen_p";
!	string_P, integer_P;

procedure string_P;
	α 
	BOOLEAN NEW;RPTR(ID_LIST)R1; LABEL RE_TRY;
	INSIDE_STRING_DECLARATION←TRUE;
	IF EQU(TOKEN,"NEW_STRING") THEN NEW←TRUE ELSE NEW←FALSE;
	ERROR_BUFFER←CURLINER;
	GET_TOKEN;
RE_TRY:
	R1←TOKEN_PTR;
	IF NEW 
	  THEN α IF R1=NULL_RECORD OR ID_LIST:BLOCK_LEVEL_OF_DEFN[R1]≠BLOCK_LEVEL 
			THEN r1←insert_entry(token,id_type_table)
			ELSE MODIFY_BACKUP_CONTINUE_MACRO([ 12,TOKEN &" already defined"]);
		β
	  ELSE IF R1=NULL_RECORD 
	    THEN α ERROR( 13, TOKEN &" not defined, will define"); R1←INSERT_ENTRY(TOKEN,ID_TYPE_TABLE) β;
	get_token;
	if token≠"=" THEN ERROR_REJECT(15,"Need ""="" here, continue will insert it");
	INSIDE_STRING_DECLARATION←FALSE;
	id_list:body[r1]←string_expr;
	id_list:type[r1]←string_value;
	β;

procedure integer_P;
	α ; β;
!	abort_P, note_P,comment_P,speed_factor_P;

procedure abort_P;
		α ! PRINT/ABORT/PAUSE STATEMENT FOUND;
		IF EQU(TOKEN,"PAUSE") THEN
			α
			ERROR_BUFFER←CURLINER;
			p_exp2;
			IF EXP_TYPE≠scalar_VALUE
			  THEN F_STATE(0,1102,"Need a scalar expression here for a PAUSE statement.");
			PRINT("(PAUSE "&OUTEXPR&")");
			β
		ELSE	α
			PRINT("("&TOKEN&" ");
			SPACING←SPACING+1;
			GET_TOKEN;
			IF ¬EQU(TOKEN,"(") THEN
				ERROR(1104,"Need left paren here, continue will insert it.");
			TOKEN←",";
			WHILE EQU(TOKEN,",") DO
				α
				GET_TOKEN;
				IF TYPE_OF_TOKEN=string_token THEN PRINT(dquote&TOKEN&dquote)
					ELSE α
					REJECT←TRUE;
					P_EXP;
					β;		
				GET_TOKEN;
				IF ¬EQU(TOKEN,",") AND ¬EQU(TOKEN,";") AND ¬EQU(TOKEN,")") THEN
					ERROR_REJECT(1103,"Illegal separator.  Continue"&
					" will try to insert reasonable separator.");
				β;
			IF ¬EQU(TOKEN,")") THEN
				ERROR(1104,"Need right paren here, continue will insert it.");
			SPACING←SPACING-1;
			PRINT(")");
			β;
		β;


procedure note_P;
			α
			BOOLEAN LPAR; STRING T,T2;
			LPAR←FALSE;
			T←TOKEN;
			GET_TOKEN;
			IF EQU(TOKEN,"(") THEN α LPAR←TRUE; GET_TOKEN β;
			IF TYPE_OF_TOKEN≠string_token then F_STATE(0,1102,
				"Need string expression here for "& token & " statement.")
			ELSE
				α T2←TOKEN;
				IF LPAR THEN α GET_TOKEN; IF ¬EQU(TOKEN,")") THEN ERROR(1234,
					"Parenthesis mismatch.") β;
				PRINT("( "& T & space & dquote & T2 & dquote & " )");
				β;
			β;

procedure comment_P;
	GARB←READ(semicolon_A_break);


procedure speed_factor_P;
			α
			GET_TOKEN;
			IF ¬TOKEN_EQU("←") THEN ERROR_REJECT(37, "Need ← here");
			p_exp2;
			IF EXP_TYPE≠SCALAR_VALUE THEN ERROR(36, "Need to have scalar expression for SPEED_FACTOR");
			PRINT("(SPEED_FACTOR "&OUTEXPR& " )");
			β;
! P_statement execution starts here;
LABEL RE_TRY;
INSIDE_STATEMENT←-100;
GET_TOKEN;
WHILE EQU(TOKEN,"COMMENT") DO
	α GARB←READ(semicolon_A_break);  GET_TOKEN;  β;
! TO GET RID OF DIRECTORY PAGE AMONG OTHER THINGS;

BACKUP_ERROR_BUFFER←ERROR_BUFFER←TOKEN&CURLINER;
GLOBAL_RE_TRY:
RE_TRY:

LABL←CHANGER_HEAD; ! USUALLY NULL EXCEPT WHEN INSIDE A CHANGER.;
CHANGER_HEAD←null;  LABEL_TYPE←0;
DIM_PTR←NULL_RECORD;

TRY_AGAIN:
CASE TYPE_OF_TOKEN OF
	α

[numeric_token]	MODIFY_FLUSH_MACRO([0,1,"Statement can't begin with a scalar"]);

[string_token]	MODIFY_FLUSH_MACRO([0,2,"Statement can't begin with a string"]);

[macro_token]	MODIFY_FLUSH_MACRO([0,3,"PARSER ERROR, MACRO TOKEN FOUND"]);

[metric_token]	IF DIM_PTR=NULL_RECORD
		  THEN α DIM_PTR←TOKEN_PTR; GET_TOKEN; GOTO TRY_AGAIN; β
		  ELSE MODIFY_FLUSH_MACRO([0,55,"AMBIGUOUS DIMENSIONS"]);

[id_token]	IF DIM_PTR = NULL_RECORD
		THEN
		α
		IF BLOCK_LEVEL_OF_DEFN≠0 OR TOKEN_EQU("BARM","YARM","BHAND","YHAND")
		THEN
		CASE (ID_TYPE + 3)OF
		α
		[CM_LABEL_VALUE +3]
		[CLC_LABEL_VALUE +3]
		[CH_LABEL_VALUE +3]
		[LABEL_VALUE +3]
		  α LABEL_TYPE←ID_TYPE;
		  IF DEFINED(TOKEN_PTR) THEN ERROR(22,"Label multiply used.");
		  DEFIN(TOKEN_PTR);
		  IF EQU(LABL,null) THEN LABL←TOKEN&" " ELSE ERROR(22,"Double label.");
		  check_next_token(23, NULL ,":");
		  GET_TOKEN; GO TO TRY_AGAIN;
		  β;

		[form_value +3]
		[boole_VALUE +3]
		[SCALAR_VALUE +3]
		[VECTOR_VALUE +3]
		[ROT_VALUE +3]
		[FRAME_VALUE +3]
		[PLANE_VALUE +3]
		[TRANS_VALUE +3]
		    α STRING ID, AS; RPTR(DIMENS_EXPONENT) ID_DIMEN;INTEGER ID_T,BL;
		    RPTR(ID_LIST) R1;  R1←TOKEN_PTR; BL←BLOCK_LEVEL_OF_DEFN;
		    ID←TOKEN; ID_T←ID_TYPE; ID_DIMEN←ID_LIST:DIMEN[TOKEN_PTR]; GET_TOKEN;
		    CASE TOKEN OF
		      α
		      ["←"]
			α STRING SS; GET_TOKEN;
			IF ¬EQU(TOKEN,"←")
			THEN α AS←"AS ";REJECT←TRUE;
				 IF ¬BL THEN F_STATE(0,7,"TRYING TO ASSIGN VALUE TO ARM OR DEVICE"); β
			  ELSE  AS←"PAS ";
			SS←"("&LABL&AS&id; P_EXP2;
			IF ¬CHECK_EXP_TYPE_DIMENS(ID_T,ID_DIMEN,"assignment statement")
			  THEN ERROR(121,"Type mismatch on assignment.");
			DEFIN(R1); PRINT(SS); SPACING←SPACING+1;
			PRINT(OUTEXPR); SPACING←SPACING-1; PRINT(")");
			β;

		      ["<"]
			α STRING TYPE_CLC,CLC_LAB; BOOLEAN TEMP; ! GAS FOUND;
			GET_TOKEN; TYPE_CLC←TOKEN;
			IF EQU(TOKEN,"<") 
			  THEN
			  α GET_TOKEN; 
			  IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(26,"Need = here.  Continue will insert it.");
			  β
			  ELSE IF ¬EQU(TOKEN,"=") AND ¬EQU(TOKEN,"≠") THEN F_STATE(0,27,"Bogus assignment.");
			GET_TOKEN;
			IF ID_TYPE=clc_label_VALUE
			  THEN
			  α CLC_LAB←TOKEN; GET_TOKEN;
			  IF ¬EQU(TOKEN,":") 
			    THEN α REJECT←TRUE; TEMP←FALSE;PRINT("("&LABL&"GAS "&id&" "&TYPE_CLC&" "&CLC_LAB&")"); β
			    ELSE TEMP←TRUE;
			  β
			  ELSE α REJECT←TRUE; CLC_LAB←T_GEN; TEMP←TRUE; PRINT("(CLCLAB "&CLC_LAB&")"); β;
			IF TEMP 
			  THEN
			  α PRINT("("&LABL&"GAS "&id&" "&TYPE_CLC&" ("&CLC_LAB&" CLC");
			  SPACING←SPACING+1; P_EXP; SPACING←SPACING-1; PRINT("))");
			  β;
			β;

		      ELSE MODIFY_FLUSH_MACRO([0,0,"Can't start this way"])
		      β;

		    β;

		[string_VALUE +3]
			F_STATE(0,2,"Statement can't begin with a string");

		ELSE F_STATE(0,4,"Statement can't begin this way")
		β
		ELSE MODIFY_FLUSH_MACRO([0,7,"Assignment statement can't begin with predefined constant"]);
		β
		ELSE ERROR(25, "CANNOT HAVE DIMENSION IN FRONT OF VARIABLE");

[undeclared_token]
		α STRING ID, AS; INTEGER ID_T;RPTR(DIMENS_EXPONENT) ID_DIMEN;
		RPTR(ID_LIST) POINT; ID←TOKEN; GET_TOKEN;
		CASE TOKEN OF
		  α
		  ["←"]
		    α STRING SS;GET_TOKEN;
		    IF ¬EQU(TOKEN,"←")THEN α  AS←"AS "; REJECT←TRUE; β ELSE α AS←"PAS "; β;
		    SS←"("&LABL&AS&id; P_EXP2;  ERROR_BUFFER←BACKUP_ERROR_BUFFER;
		    IF MODIFY_CONTINUE(0,"Undefined variable "&id&crlf&
				"Continue will declare it . Modify will allow correction.")
		      THEN GOTO TRY_AGAIN
		      ELSE
		      α POINT←INSERT_ENTRY(ID,ID_TYPE_TABLE);
		      ID_LIST:TYPE[POINT]←EXP_TYPE; ID_LIST:DIMEN[POINT]←EXP_DIMENS;
		      IF EXP_TYPE=Trans_VALUE THEN ID_T←frame_VALUE ELSE ID_T←EXP_TYPE;
		      PRINT("("&DEC_NAME[ID_T]&"  "&ID&")");
		      DEFIN(POINT); PRINT(SS); SPACING←SPACING+1;
		      PRINT(OUTEXPR); SPACING←SPACING-1; PRINT(")");
		      β;
		    β;

		  ["<"] 
		    α STRING TYPE_CLC,CLC_LAB; BOOLEAN TEMP; ! GAS FOUND;
		    RPTR(ID_LIST) POINT; POINT←INSERT_ENTRY(ID,ID_TYPE_TABLE);
		    ID_LIST:TYPE[POINT]←trans_VALUE; DEFIN(POINT);
		    GET_TOKEN; TYPE_CLC←TOKEN;
		    IF EQU(TOKEN,"<") 
		      THEN
			α GET_TOKEN;
			IF ¬EQU(TOKEN,"=") THEN ERROR_REJECT(26,"Need = here.  Continue will insert it.");
			β
		      ELSE IF ¬EQU(TOKEN,"=") AND ¬EQU(TOKEN,"≠") THEN F_STATE(0,27,"Bogus assignment.");
		    GET_TOKEN;
		    IF ID_TYPE=clc_label_VALUE
		      THEN
		      α CLC_LAB←TOKEN; GET_TOKEN;
		      IF ¬EQU(TOKEN,":") 
			THEN
			α REJECT←TRUE; TEMP←FALSE;
			PRINT("("&LABL&"GAS "&id&" "&TYPE_CLC&" "&CLC_LAB&")");
			β
			ELSE TEMP←TRUE;
		      β
		      ELSE α REJECT←TRUE; CLC_LAB←T_GEN; TEMP←TRUE; PRINT("(CLCLAB "&CLC_LAB&")"); β;
		    IF TEMP 
		      THEN
		      α PRINT("("&LABL&"GAS "&id&" "&TYPE_CLC&" ("&CLC_LAB&" CLC");
		      SPACING←SPACING+1; P_EXP; SPACING←SPACING-1; PRINT("))");
		      β;
		    β;

		  ELSE MODIFY_FLUSH_MACRO([0,25,"Can't start statement this way"])
		  β;
		β; 

[reserved_token]	
		α INSIDE_STATEMENT←RESERVED_TOKEN_PTR;
		IF (statement_beg ≤ TYPE_OF_RES_WORD ≤ statement_end) 
		  THEN CASE TYPE_OF_RES_WORD - statement_beg OF
		  α
		  redefine xx(str)=[redefine xx_temp="str" & "_P";  xx_temp;];
		  redefine yy(str)=[];
		  redefine zz(str)=[redefine zz_temp="str" & "_P";  zz_temp;];
		  statement_definitions;
		  β
		  ELSE IF TOKEN_PTR←CHECK_ENTRY(TOKEN,DIMENSION_TYPE_TABLE)
		    THEN α TYPE_OF_TOKEN←METRIC_TOKEN;
			   DIM_PTR←TOKEN_PTR;  GOTO TRY_AGAIN; β
		    ELSE MODIFY_FLUSH_MACRO([0,3,"Statement can't begin with <"&TOKEN&">"]);
		β
	β;
FLUSH:


β "P_STATEMENT";
! execution starts here, initialization;

    procedure update_break_RS;
	α  
	SETBREAK(word_R_break, TABLE1, NULL, "INRK");
	SETBREAK(word_S_break, TABLE1, NULL, "INSK");
	β;

    procedure add_to_table1(string s);
	α  TABLE1←TABLE1&S;
	update_break_RS;
	β;

    procedure remove_from_table1(string s);
	α
	integer temp;
	setbreak(temp←getbreak,null,s,"O");
	TABLE1←SCAN(TABLE1,TEMP,BRCHAR);
	update_break_RS;
	RELBREAK(TEMP);
	β;
α "execution"
INITIALIZE←TRUE;
COUNT ← 1000;  DELIMITER_1 ← DELIMITER_2 ← 0;  top_delimiters ← null_record;
OPEN_BRACE← "{" ;
TABLE1 ← "⊂⊃%,.;:[](){}+-*/#∧∨¬⊗&≤≥<>≠=←↑→?|" & lf & cr & dquote & tab & ff & space & squote ;
								SETBREAK(
word_R_break	← getbreak, TABLE1, NULL, "INRK");
								SETBREAK(
non_blank_break	← getbreak, space & crlf & ff & tab, NULL, "XNRK");
								SETBREAK(
word_S_break	← getbreak, TABLE1, NULL, "INSK");
								SETBREAK(
non_digit_break	← getbreak, ".0123456789", NULL, "XRK");
								SETBREAK(
close_brace_break← getbreak, "}", NULL, "ISK");
								SETBREAK(
quote_break	← getbreak, dquote, NULL, "ISN");
								SETBREAK(
semicolon_A_break← getbreak, ";", NULL, "IAK");
								SETBREAK(
cr_break	← getbreak, cr, NULL, "IANK");
								SETBREAK(
paren_cr_break	← getbreak, "()" & cr, NULL, "IANK");
								SETBREAK(
lf_ff_break	← getbreak, lf & ff, NULL, "IANK");
								SETBREAK(
semicolon_R_break	← getbreak, ";", NULL, "IRK");
								SETBREAK(
omit_break	← getbreak, NULL, ";,." & ff & crlf, "I");
								SETBREAK(
tty_input_break	← getbreak,ALT,NULL,"IS");

macro_delimiter_break ← getbreak;

TTYUP(TRUE);

! set up input and output;

if rpgsw then
    α
    cmd_line ← tmpin("AL", eof);
    if eof
	then α usererr(0, 1, "TMPIN lost"); rpgsw ← false β
	else outstr(crlf & "AL:  ");
    β;
if ¬rpgsw then α outstr(crlf & "*"); cmd_line ← instrl(cr) β;
BIN_file ← new_record(file);  ALL_file ← new_record(file);
SEX_file ← new_record(file);	T←TRUE;

while true do
    α "command" define want_BAIL=[switch_setting[b_X]];

    want_BAIL ← false;
    if ¬T then α outstr(crlf & "*"); cmd_line ← instrl(cr) β;  T ← false;
    PRESENT_file←AL_file ← scan_command(cmd_line, BIN_file, ALL_file);
    if file:eof[AL_file] then
	α usererr(0, 1, "null input spec"); continue "command" β;

    file:mode[AL_file] ← 0; file:in_bfrs[AL_file] ← 12; file:out_bfrs[AL_file] ← 0;
    file:def_ext[AL_file] ← "AL";
    if ¬got_input(AL_file) then
	α outstr(infile & "file not found"); continue "command" β;
    if file:name[BIN_file]=null 
      then if file:name[AL_file]= null 
	then file:name[BIN_file]←"ALMAIN"
	else file:name[BIN_file]←file:name[AL_file];

    copy_file_record(SEX_file, BIN_file);
    file:mode[SEX_file] ← 0; file:in_bfrs[SEX_file] ← 0;
    file:out_bfrs[SEX_file] ← 12;  file:ext[SEX_file] ← "SEX";
    if file:eof[SEX_file] then
	α "null output spec"
	file:device[SEX_file] ← "DSK";
	if file:name[AL_file]≠null
	  then file:name[SEX_file] ← file:name[AL_file]
	  else file:name[SEX_file] ← "ALMAIN" ;
	β "null output spec";
    if ¬got_output(SEX_file) then
	α usererr(0, 1, "can't get output"); continue "command" β;
    outfile←make_file_name(SEX_file);
    chanin ← file:chn[AL_file]; chanout ← file:chn[SEX_file];

   if equ(file:device[PRESENT_file],"TTY") 
     then
     α 
     CHECK_WANT_COPY;
     OUTSTR(CRLF&"Enter input through the keyboard. Terminate with<CONTROL><META><LF>"&CRLF);
     β
     else
     α if typed_page_num then outstr(crlf);
     outstr(infile & " 1");
     CHANTTYO←-1;
     β;
    pagenum ← linenum ← sourcelvl ← 0;
    typed_page_num ← true;
    ifc debug_compile thenc if want_BAIL then BAIL; endc
    done "command"
    β "command";
! set up predefined dimensions, constants, macros and variables;
redefine zz(temp)=[];
redefine yy(temp,temp2)=[
	redefine xx_temp= "DIMENS_EXPONENT:"&"temp"&"["&"temp"&"_DIMENS]←1;";
		qq(temp)
		xx_temp];
redefine qq(temp)=[redefine xxcount=xxcount+1;
	redefine yytemp= "temp"&"_DIMENS←NEW_RECORD(DIMENS_EXPONENT);";
	redefine zztemp= "DIMENS_EXPONENT:NAME["&"temp"&"_DIMENS]←"&""""&"temp"&""""&";";
	redefine xxtemp(xxxcount)= 
		"D_TABLE["&"xxxcount" & "] ← INSERT_ENTRY("&""""&"temp"
			&""""&",DIMENSION_TYPE_TABLE,"&"temp"&"_DIMENS);";
		yytemp
		zztemp
		xxtemp(xxcount)];
redefine xxcount=-1;
metric_definitions;

INSERT_ENTRY("DIMENSIONLESS",DIMENSION_TYPE_TABLE);

VELOCITY_DIMENS←DIVIDE_DIMENSIONS(DISTANCE_DIMENS,TIME_DIMENS);
TORQUE_DIMENS ← MULTIPLY_DIMENSIONS(FORCE_DIMENS,DISTANCE_DIMENS);
ANGULAR_VELOCITY_DIMENS←DIVIDE_DIMENSIONS(ANGLE_DIMENS,TIME_DIMENS);

FOR I←1 STEP 1 UNTIL const_count DO
	α RPTR (ID_LIST) TEMP;
	INSERT_ENTRY(PRECONST[I],ID_TYPE_TABLE,TEMP←NEW_RECORD(ID_LIST));
	ID_LIST:TYPE[TEMP]←PRECONST_TYPE[I];
	ID_LIST:DIMEN[TEMP]←D_TABLE[PRE_DIMENS[I]];
	DEFIN(TEMP);
	β;

ID_LIST:BODY[CHECK_ENTRY("CRLF",ID_TYPE_TABLE)]← "
";

redefine xx(str1, str2)=[
	MACRO_LIST:VALUE[cur_macro←INSERT_ENTRY("str1",MACRO_TYPE_TABLE)]←"str2";
	macro_list:delimiters[cur_macro]←"⊂⊃";
	cur_macro←null_record;
	];
macro_definitions;

INITIALIZE←FALSE;
! PARSE PROGRAM;
RUNTIME←___TIME;
spacing ← 0;  print("(PR");  SPACING ← 1; BLOCK_LEVEL←0;
! **********;     P_STATEMENT;     ! **********;

IF TOP_SOURCE≠NULL_RECORD OR ¬EQU(INPUT(CHANIN,omit_break),null) THEN
	ERROR(200,"Misc. garbage found after last end.");
spacing ← 0;  print(")");

RUNTIME←___TIME - RUNTIME;
! CLEAN UP;
IF CHANIN≠-1 THEN RELEASE(CHANIN);
WHILE TOP_SOURCE≠NULL DO
    α
    IF SOURCE_LIST:CHAN[TOP_SOURCE]≠-1 THEN RELEASE(SOURCE_LIST:CHAN[TOP_SOURCE]);
    TOP_SOURCE←SOURCE_LIST:NEXT[TOP_SOURCE];
    β;
CLOSO(CHANOUT);
CLOSO(CHANLOG);
OUTSTR(CRLF & "PARSING TIME		 = "&CVS(RUNTIME)& " MSECS");
IF NUM_OF_ERRORS > 0 THEN
	α
	OUTSTR(crlf & "Number of errors found    = "& cvs(NUM_OF_ERRORS));
	OUTSTR(CRLF & "Number of errors modified = "& cvs(NUM_OF_ERRORS_MODIFIED));
	β;
β "execution";
! SWAP TO AL COMPILER;


α "swap" integer array swap[0:10];  string s;  integer tmperr;
if length(file:ext[BIN_file])=0 then file:ext[BIN_file] ← "BIN";
s ← make_file_name(BIN_file) & "," & make_file_name(ALL_file) & "←" & outfile;
    α "switches_for_ALC" boolean seen_one;  integer i;
    seen_one ← false;
    for i ← 0 step 1 until switch_max do
	if switch_setting[i] then
	    α
	    if ¬seen_one then α s ← s & "("; seen_one ← true β;
	    s ← s & switch_name[i];
	    β;
    if seen_one then s ← s & ")";
    β "switches_for_ALC";
tmpout("ALC", s, tmperr);
if tmperr then usererr(0, 1, "Trouble with TMPOUT");
outstr(crlf);

swap[0] ← cvsix("DSK");  swap[1] ← cvfil("ALC.DMP[AL,HE]", swap[2], swap[4]);
swap[3] ← 1;  ! start job in RPG mode;  swap[5] ← 0;
call(location(swap[0]), "SWAP");
β "swap";


β "hidden_parse";

HIDDEN_PARSE;
END "PARSE";